石子歸併 區間DP

2021-09-10 17:41:47 字數 1764 閱讀 3437

n堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將n堆石子合併成一堆的最小代價。

例如: 1 2 3 4,有不少合併方法

1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)

1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)

1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括號裡面為總代價可以看出,第一種方法的代價最低,現在給出n堆石子的數量,計算最小合併代價。

輸入第1行:n(2 <= n <= 100)

第2 - n + 1:n堆石子的數量(1 <= a[i] <= 10000)

輸出輸出最小合併代價

輸入樣例41

234輸出樣例

19在沒學習dp前,我會把這題考慮成為乙個貪心題;

要使合併代價最小,我們可以使權值較大的最後合併,減少權值較大的計算次數來減少最小合併代價;

即區域性考慮最優,然後整體最優;這是貪心的思想,但是這個結論卻是錯誤的;

舉個例子解釋一下,

46 5 5 6

我們第一步選擇合併代價最小的,即合併5 和 5

新的石子堆 6 10 6 此時代價 = 10 。然後我們再次合併所需代價最小的;即合併6 10

新的石子堆 16 6 代價 = 10 + 16。 然後再次合併

新的石子堆 2 2 代價 = 10 + 16 + 22 = 48

按照貪心的思想, 我們使得區域性最優得到的解時是 48 , 這個結果對不對呢?答案是錯誤的;比如

我們第一步合併6,5.得到 11 5 6 代價為 11

我們第二步合併5,6.得到 11 11 代價為 11 + 11

我們第三步合併11,11.得到 22 代價為 11 + 11 + 22 = 44;

顯然區域性最優並非整體最優,所以我們得用動態規劃來求解;

我們可以定義狀態dp[i][j]代表從i到j的合併所需的最小代價;

狀態轉移方程就是 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + val);

這裡的val指的是當i->k已經合併為1堆,k+1->j合併為一堆;合併這兩堆的代價;

在本題中就是i->j的乙個區間和,我們可以用字首和來維護一下就可以;

我們在最外層列舉選取合併長度,第二層列舉起點,第三層列舉分割點即可;

演算法複雜度為o(n^3);

計算最小代價初始化為inf;

計算最大代價初始化為-inf;

#include

using namespace std;

#define long long long

#define inf 0x3f3f3f3f

#define max_n 110

int a[max_n]

, sum[max_n]

, dp[max_n]

[max_n]

;//a記錄輸入資料 sum為字首和

intmain()

}for

(int i =

1; i <= n; i++

)//錄入資料並計算字首和

for(

int k =

1; k <= n; k++

)//列舉選取長度}}

cout << dp[1]

[n]<< endl;

return0;

}

石子歸併(區間DP)

測評傳送門 題目描述 有n堆石子排成一列,每堆石子有乙個重量w i 每次合併可以合併相鄰的兩堆石子,一次合併的代價為兩堆石子的重量和w i w i 1 問安排怎樣的合併順序,能夠使得總合併代價達到最小。輸入描述 第一行乙個整數n n 100 第二行n個整數w1,w2.wn wi 100 輸出描述 乙...

區間dp石子歸併問題

石子歸併 現在有n堆石子,第i堆有ai個石子。現在要把這些石子合併成一堆,每次只能合併相鄰兩個,每次合併的代價是兩堆石子的總石子數。求合併所有石子的最小代價。input 第一行包含乙個整數t t 50 表示資料組數。每組資料第一行包含乙個整數n 2 n 100 表示石子的堆數。第二行包含n個正整數a...

區間dp 石子歸併問題

今天偷玩電腦,就學了幾個模板題,水一水吧 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。分析 要求n個石子歸併,我們根據dp的思想劃分成子問題,...