石子合併 (區間DP

2021-06-08 07:17:00 字數 2258 閱讀 2457

【問題描述】

在乙個操場上擺放著一行共n堆的石子。現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請編輯計算出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。

【輸入檔案】

輸入第一行為n(n<1000),表示有n堆石子,第二行為n個用空格隔開的整數,依次表示這n堆石子的石子數量(<=1000)

【輸出檔案】

輸出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。

【輸入樣例】 3

1 2 3

【輸出樣例】

9 11

【問題分析】

人們那到這類題目的第一想法是貪心(找最大/最小的堆合併),但是很容易找到貪心的反例:(以求最小為例)

貪心:

3  4  6  5 4  2

5  4  6  5 4        得分:5

9  6  5 4           得分:9

9  6 9             得分:9

15 9               得分:15

24                  得分:24

總得分:62

合理方案

3  4  6  5 4  2

7  6  5  4 2        得分:7

7  6  5 6           得分:6

7  11 6             得分:11

13 11              得分:13

24                  得分:24

總得分:61

也就是說第二個4 和2 合併要比和5合併好,但是由於一開始2被用了沒辦法它只好和5合併了……

既然貪心不行,資料規模有很大,我們自然就想到用動態規劃了。

*不過要知道某個狀態下合併後得分最優就需要知道合併它的總得分,只有對子問題的總得分進行最優的判斷,設計的狀態才有意義。

*但要是想知道總分,就要知道合併一次的得分,顯然這個含義不能加到動態規劃的狀態中,因為一般乙個狀態只代表乙個含義(也就是說opt[i]的值只能量化乙個問題)(上面代*號的兩段比較抽象,不懂可以不看。我只是為了標註自己的理解加的,不理解的也沒必要理解。)

先要把題目中的環變成鏈,這樣好分析問題。具體方法:把環截斷,複製乙份放到截斷後形成的鏈的後面形成乙個長度是原來兩倍的鏈(只有環中的元素在處理時不隨著變化,就可以這樣做。其實讀入資料已經幫你截斷了);

例: 3 4 5

變成 3 4 5 3 4 5

對於這樣乙個鏈,我們設計乙個狀態opt[i,j]表示起點為i終點為j的鏈合併成一堆所得到的最優得分。

要合併乙個區間裡的石子無論合併的順序如何它的得分都是這個區間內的所有石子的和,所以可以用乙個陣列sum[i]存合併前i個石子的得分。

因為合併是連續的所以決策就是把某次合併看作是把某個鏈分成兩半,合併這想把兩半的好多堆分別合併成一堆的總得分+最後合併這兩半的得分;

狀態轉移方程:

maxopt[i,j]=max+sum[j]-sum[i-1]

minopt[i,j]=min+sum[j]-sum[i-1]

複雜度:狀態數o(n2)*決策數o(n)=o(n3)

#include#include#includeusing namespace std;

const int inf = 999999999;

int num[300], sum[300], n;

int dpmx[300][300], dpmn[300][300];

int main()

sum[0] = num[0];

for(i = 1; i < 2 * n; i++)

sum[i] = sum[i-1] + num[i];

for(i = 0; i < 2 * n; i++)

for(j = i; j < 2 * n; j++)

dpmx[i][j] = -inf, dpmn[i][j] = inf;

for(i = 0; i < 2 * n; i++)

dpmx[i][i] = dpmn[i][i] = 0;

for(k = 1; k < n; k++)}}

int retmx = -inf;

int retmn = inf;

for(i = 0; i + n - 1 < 2 * n; i++)

printf("%d\n%d\n",retmn,retmx);

}return 0;

}

石子合併 區間dp

有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。假設dp 1 4 表示將區間1 4的石子合併所花費的代價。dp 1 4 可以劃分為dp 1 1 dp 2...

石子合併 (區間DP)

題目鏈結 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。輸入第一行有乙個整數n,表示有n堆石子。接下來的一行有n 0 n 200 個數,分別表示...

區間DP 石子合併

區間dp的經典例題,有三種題型 本篇部落格借鑑了了兩位大佬的部落格。部落格1 部落格2 問題 n堆石子,現要將石子有序的合併成一堆。每次只能移動任意的2堆石子合併,合併花費為新合成的一堆石子的數量。求將這n堆石子合併成一堆的總花費最小 或最大 思路 貪心,每次把最小的兩堆合併即可,可以使用stl中的...