【洛谷】P1880 石子合併

 P1880 石子合併

題目描述

在一個園形操場的四周擺放N堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記爲該次合併的得分。

試設計出1個算法,計算出將N堆石子合併成1堆的最小得分和最大得分.

輸入輸出格式

輸入格式:

數據的第1行試正整數N,1≤N≤100,表示有N堆石子.第2行有N個數,分別表示每堆石子的個數.

輸出格式:

輸出共2行,第1行爲最小得分,第2行爲最大得分.

輸入輸出樣例


這是一道區間dp十分經典的模板題,讓我們揣測一下,前輩們是如何得到這個狀態轉移方程的。
首先,要計算合併的最大值、最小值,既然是動態規劃,我們需要洞悉其中一些關聯且確定的狀態。
以下以最大值爲例。
既然是最大值,那麼求得的結果是否滿足每一區間都是該區間所能達得到的的最大值?
顯然是這樣的。反證法:倘若有一個區間不是,那麼換做該區間取得最大值的方案,最終結果將比原得分大。顯然必定滿足任意區間得分一定是該區間內的最大值。
這樣我們可以定義狀態f[i][j],表示i到j合併後的最大得分。其中1<=i<=j<=N。
既然這樣,我們就需要將這一圈石子分割。很顯然,我們需要枚舉一個k,來作爲這一圈石子的分割線。
這樣我們就能得到狀態轉移方程:
f[i][j] = max(f[i][k] + f[k+1][j] + d(i,j));其中,1<=i<=<=k<j<=N。
d(i,j)表示從i到j石子個數的和。
那麼如何編寫更快的遞推來解決這個問題?
在考慮如何遞推時,通常考慮如下幾個方面:
是否能覆蓋全部狀態?
求解後面狀態時是否保證前面狀態已經確定?
是否修改了已經確定的狀態?
也就是說,在考慮遞推順序時,務必參考動態規劃的適應對象多具有的性質,具體參考《算法導論》相關或百度百科或wiki。
既然之前說過我們需要枚舉k來劃分i和j,那麼如果通過枚舉i和j進行狀態轉移,很顯然某些k值時並不能保證已經確定過所需狀態。
如,i=1 to 10,j=1 to 10,k=1 to 9.當i=1,j=5,k=3時,顯然狀態f[k+1][j]沒有結果。
那麼,我們是不是應該考慮枚舉k?
但這樣i和j就難以確定了。
我們不難得到一個兩全的方法:枚舉j-i,並在j-i中枚舉k。這樣,就能保證地推的正確。

上代碼。
#include<iostream>
#include<cstdio>
#include<cmath>

using namespace std; 

int n,minl,maxl,f1[300][300],f2[300][300],num[300];
int s[300];
inline int d(int i,int j){return s[j]-s[i-1];}
//轉移方程:f[i][j] = max(f[i][k]+f[k+1][j]+d[i][j];               

int main()
{ 
    scanf("%d",&n);
    for(int i=1;i<=n+n;i++)
    {
        scanf("%d",&num[i]);
        num[i+n]=num[i];
        s[i]=s[i-1]+num[i];
    }
    for(int p=1;p<n;p++)
    {
        for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p)
        {
            f2[i][j]=999999999;
            for(int k=i;k<j;k++)
            {
                f1[i][j] = max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j)); 
                f2[i][j] = min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j));
            }
        }
    }
    minl=999999999;
    for(int i=1;i<=n;i++)
    {
        maxl=max(maxl,f1[i][i+n-1]);
        minl=min(minl,f2[i][i+n-1]);
    }
    printf("%d\n%d",minl,maxl);
    return 0;
}

邊界狀態還望讀者仔細思考(不懂請留言)

放寒假了,是時候刷一波dp過過癮了。

發佈了40 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章