時間限制:2.0s 記憶體限制:256.0mb
問題描述
在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。
輸入格式
輸入第一行包含乙個整數n,表示石子的堆數。
接下來一行,包含n個整數,按順序給出每堆石子的大小 。
輸出格式
輸出乙個整數,表示合併的最小花費。
樣例輸入
51 2 3 4 5
樣例輸出
33資料規模和約定
1<=n<=1000, 每堆石子至少1顆,最多10000顆。
思路:
題目意思就是在n堆石子中不斷的合併相鄰的石頭直到合併成1堆,然後叫我們算出最小花費。題目的花費情況是合併的費用為兩堆石子的總數,意思就是當我們合併1和2 那麼花費就是3 合併的3和之前的3合併花費總和就是3+3+3=9還要加之前的花費。
那我們可以分解此題,假設我們有1個石頭那花費是0,2個石頭那麼就是他們的總和,3個石頭那我們怎麼劃分呢,我們可以把他分解出來 :
第一種我們可以將前面(第1堆和第2堆合併的花費值+第3堆花費值)+他們3個石頭的數量=總花費值 (因為花費值並沒有把本身的石頭值加到花費裡面。)
第二種(第2堆和第3堆合併的花費值+第1堆花費值)+他們3個石頭的數量=總花費值 依次類推…
那我們從上面可以知道可以用動態規劃的方式完成。
我們可以先把第1堆到n的每個區域儲存起來我儲存到了ad列表中。我們在建立乙個dp[j][j1]表示j-j1之間的最小花費。
我們建立2層for迴圈第一層表示長度 第二層表示當前開頭的堆 那 堆尾=開頭+長度
從上述可知我們需要把這n堆石子的可能性列出來。那我們就建立乙個for 從j-j1 因為我們遍歷的是當前的n堆的可能性,那麼dp[j][k] 表示的是前面j-k的堆 後面那麼就表示 dp[k+1][j1], 這就是我們合併所花費的值。並沒有把本身的石頭值加到花費裡面。所以還要加ad[j1]-ad[j-1].
那麼我們的轉移方程就是:dp[j][k]+dp[k+1][j1]+ad[j1]-ad[j-1]
然後在和本身的數比較最小值:
min(dp[j][j1],dp[j][k]+dp[k+1][j1]+ad[j1]-ad[j-1]) 注意我是從1開始的。
程式:
n=
int(
input()
)a=list
(map
(int
,input()
.split())
)dp=[[
999999999999
for i1 in
range
(n+5)]
for i in
range
(n+5)]
#dp初始化
ad=[
0for i in
range
(1005)]
for i in
range(1
,n+1):
ad[i]
=ad[i-1]
+a[i-1]
#把第0堆到i的每個區域儲存起來
dp[i]
[i]=
0#1堆最小花費為0
for i in
range(1
,n+1):
#表示j+i之間的堆 可以說是當前的長度。
for j in
range(1
,n-i+1)
:#當前開頭堆
j1=i+j #結尾堆
for k in
range
(j,j1+1)
:#把這n堆石子的可能性列出來
dp[j]
[j1]
=min
(dp[j]
[j1]
,dp[j]
[k]+dp[k+1]
[j1]
+ad[j1]
-ad[j-1]
)print
(dp[1]
[n])
演算法提高 合併石子(DP)
問題描述 在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。輸入格式 輸入第一行包含乙個整數n,表示石子的堆數。接下來一行,包含n個整數,按順序給出每堆石子的大小 輸出格式 輸出乙個整數,表...
演算法提高 合併石子 動態規劃
問題描述 在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。輸入格式 輸入第一行包含乙個整數n,表示石子的堆數。接下來一行,包含n個整數,按順序給出每堆石子的大小 輸出格式 輸出乙個整數,表...
藍橋杯 演算法提高 合併石子 (dp)
演算法提高 合併石子 時間限制 2.0s 記憶體限制 256.0mb 問題描述 在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。輸入格式 輸入第一行包含乙個整數n,表示石子的堆數。接下來一...