DP之石子堆合併問題

2022-06-13 09:36:12 字數 3060 閱讀 5847

(1)相鄰:在乙個圓形操場的四周擺放著n堆石子(n<= 100),現要將石子有次序地合併成一堆。規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。選擇一種合併石子的方案,使得做n-1次合併,得分的總和最小。

1/*2

* 在乙個圓形操場的四周擺放著n堆石子(n<= 100),現要將石子有次序地合併成一堆。

3* 規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。

4*選擇一種合併石子的方案,使得做n-1次合併,得分的總和最小。5*/

6public

static

void test(int

a) 14

int sum=0;

15 system.out.println("score:"+sum);

16for(int r=1;r<=a.length-1;r++) 28}

2930

for(int i=0;i) else

if(i==index1)36}

37 sum+=min;

38 system.out.println("score:"+sum);39}

40 }

思路就是類似矩陣連乘,關鍵就是最優解不好表示或者我寫的有問題。。。(明天再來改!!!今天累了)ok得出結論了就是我的想法有問題。

下面是標準dp:

設dp[i][j]表示第i到第j堆石子合併的最優值(合併i-j的花費的最小力氣),sum[i][j]表示第i到第j堆石子的總數量。那麼就有狀態轉移公式: 

因為每乙個石子堆無非是和左邊合併或者先和右邊合併。對第i到第j的每乙個k(子問題)計算他們的最小值加上每堆石子的總數量因為最後一步總是把所有的都合併。

我們可以從最小問題想起來:假如這個陣列只有三個數,那麼最小力氣就是min(左邊兩個,右邊兩個)+三個的總量(最後一步)

有四個數時,將它們分為1-3,2-4兩個子問題再繼續分...

1

public

static

void testa(int

a) 9}10

//b[i][j]表示第i堆到第j堆的最優合併值

11intb=new

int[a.length][a.length];

12//

s表示i到j的和

13ints=new

int[a.length][a.length];

14//

儲存最優解 0左 1下

15intl=new

int[a.length][a.length];

16 stackstack=new stack();

17//

賦初值18

for(int i=0;i)

2223

for(int r=1;r<=a.length-1;r++) else 34}

35}36int x=0,y=a.length-1;

37for(int i=0;i)

4445

while(!stack.isempty())

53system.out.println("score:"+b[p.start][p.end]);54}

55 }

(2)環形:就是不是相鄰的是成環的最簡單的就是窮舉相鄰的找出最小的。這個時候把上面函式的返回值設為int然後計算。

第二種方法是將兩邊各擴充套件一位。因為只和左右相關邊界位置應與頭尾相連,然後進行相同的計算,最後在幾種方案中挑出最小的。

1

public

static

void testb(int

a) 9}10

//首尾相連

11intb=new

int[a.length+2];

12 b[0]=a[a.length-1];

13 b[b.length-1]=a[0];

14for(int i=0;i)

1718

//i-j的最優

19intd=new

int[b.length][b.length];

20//

sum21

ints=new

int[b.length][b.length];

22//

最優解0左 1下

23intl=new

int[b.length][b.length];

24 stackstack=new stack();

25//

賦初值26

for(int i=0;i)

30//

可以不填滿,只填到需要的就行

31int min=-1;

32 point end=new point(-1,-1);

33for(int r=1;r<=a.length-1;r++) else

44if(r==a.length-1)

51else

if(min>d[i][j])

5257}58

}59}60

int x=end.start,y=end.end;

61for(int i=0;i)

68while(!stack.isempty())

76 system.out.println("score:"+d[p.start][p.end]);77}

78 }

(3)總結

這個是典型的dp問題,因為已經處理過之前的矩陣連乘問題,所以一開始我陷入了固定思維只想著填表,而沒有去找子問題一步一步來。本末倒置。導致思路很不清晰但是**似乎更簡短。在處理環形時,選取了在兩邊擴充套件一位再每次分組計算最後取出一部分。

dp 石子合併問題

問題描述 在乙個圓形操場的四周擺放著n 堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰 的2 堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。程式設計任務 試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。資料輸入 包含兩行,第1 行是正整數n 1 n 100 ...

dp 石子合併問題

石子合併問題 有n n 100 堆石子,價值分別為a0,a1.a n 1 每次將其中的相鄰的兩堆合併,合併的代價為兩堆石子的價值和,合併後用合併之後的一堆石子代替之前的兩堆石子,價值為原來 兩堆價值之和,求最終將所有的石子合併成一堆之後的代價最小值。問題一 n堆石子排成一條直線 這個問題比較簡單,類...

演算法 石子堆合併問題

問題描述 一維陣列的每一項表示乙個石子堆,將相鄰兩個石子堆 合併 指的是,將相鄰兩個陣列元素加到一起,並需要付出代價 即兩堆石子的重量之和 求合併到一堆過程中損耗的價值最少為多少 如,1,3,2,5,4 3,2合併 1,5,5,4 代價5 1,5合併,6,5,4 代價6 4,5合併 6,9 代價9 ...