首先我們要搞懂什麼是動態規劃。我覺得動態規劃就是把乙個大問題分解為多個小問題,每個小問題的決策都會影響到下乙個小問題的決策。(下乙個小問題的決策就是由上乙個小問題的決策而產生的。)乙個狀態經過乙個決策變成了另外乙個狀態,這個過程就是狀態轉移,用來描述狀態轉移的方程就是狀態轉移方程。
在乙個操場上一排地擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請設計乙個程式,計算出將n堆石子合併成一堆的最小得分。
我們首先來分析乙個比較簡單的問題,現在一共有三堆石頭,每堆石子的數量分別是3,4,11。求合併成一堆石頭的最小得分。
對於這個問題,只有兩種選擇:
前兩堆石頭合併再和第三堆石頭合併。
3+4=7 ——> 7 石堆變為(7, 11)
7+11=18——>18 石堆變為(18)
cost=7+18=25
後兩堆石頭合併再和第一堆石頭合併。
4+11=15——>15 石堆變為(3,15)
3+15=18——>18 石堆變為(18)
cost=15+18=33
易看出先合併前兩堆的石子的花費比較小,不同的合併方式會造成不同的得分。同時可以發現這兩種方法最後一次的得分就是石頭的總數。
現在我們用乙個陣列arr按順序儲存每個位置的石頭數量。
arr=
二維陣列sum[i][j]表示第i堆石頭到第j堆石頭的總和
sum[0][1]=3+4=7;
sum[1][2]=4+11=15;
sum[0][2]=3+4+11=18;
最後用乙個二維陣列dp[i][j]表示從第i堆到第j堆石頭合併的最小分數。
1)每堆石頭跟自己合併的分數都是0。
dp[0][0]=dp[1][1]=dp[2][2]=0
2)相鄰兩堆石頭的最小合併分數只有一種可能。
dp[0][1]=3+4=7, dp[1][2]=4+11=15
3)剩下的就是不相鄰石頭的合併最小花費。
設乙個k∈[i,j];
dp[i][j]=dp[i][k]+dp[k][j]+sum[i][j];
那麼從i到j的所有花費都可以表示出來了,取乙個使得dp[i][j]最小的值。
我們用**來表示出從i到j的費用最小值。(對於c來說一般是序號從0開始)
dp[1][3]=min(dp[1][1]+dp[2][3] , dp[1][2]+dp[3][3])+sum[1][3];
dp[2][4]=min(dp[2][3]+dp[4][4] , dp[2][2]+dp[3][4])+sum[2][4];
dp[1][4]=min(dp[1][1]+dp[2][4],dp[1][2]+dp[3][4],dp[1][3]+dp[4][4])+sum[1][4];
我們最終的目的是求出dp[1][4],那我們就要先求出dp[1][3]和dp[2][4],從影象上我們要求最右上角的值,就是沿著副對角線一步步往上求。
思路就是這樣了,下面是**。
#include
intmain()
for(i=
0; i
)else
sum[i]
[j]=sum[i]
[j-1
]+arr[j];}
}//計算從i到j的石頭總和
for(i=
0; i
//把同一堆石頭和相鄰兩堆石頭合併的值計算
for(t=
2; t<=n; t++)}
if(a<=b)
else
dp[i]
[i+t]
=b;}
}//按照**從副對角線往依次計算的方法,最後求出右上角的值
printf
("%d"
,dp[0]
[n-1])
;return0;
}
有更好的方法歡迎交流~~
想學動態規劃的可以看看這篇文章:告別動態規劃,連刷40道動規演算法題,我總結了動規的套路。
動態規劃專題之石子合併
動態規劃專題講義 專題九 合併石子問題 name 動態規劃專題之石子合併 author 巧若拙 description 在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合...
動態規劃 石子合併
題目描述 在乙個圓形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入輸出格式 輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石...
石子合併動態規劃
在乙個園形操場的四周擺放n堆石子 n 100 現要將石子有次序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,由檔案讀入堆數n及每堆的石子數 20 選擇一種合併石子的方案,使得做n 1次合併,得分的總和最小 選擇一種合併石子的方案,使得做n ...