【題目地址】
http://acm.hdu.edu.cn/showproblem.php?pid=3506
【題目大意】
香蕉森林裏一羣猴子(n<=1000)圍成一圈開會,會長給他們互相介紹,每個猴子需要時間a[i]。每次只能介紹相鄰的兩隻猴子x和y認識,同時x所有認識的猴子和y所有認識的猴子也就相互認識了,代價爲這兩夥猴子認識的時間(a[])之和。
求這羣猴子都互相認識的最短時間。
PS:My English is very poor, so you may not understand what I had said。It does not matter, just regarding it as a problem of stone merging(石子歸併).
【解題思路】
令f[i,j]表示歸併第i個數到第j數的最小代價,sum[i,j]表示第i個數到第j個數的和,這個可以事先計算出來。sum[i,j]可以在O(1)的時間內算出.
容易的到以下的動態轉移方程:
階段:以歸併石子的長度爲階段,一共有n-1個階段。
狀態:每個階段有多少堆石子要歸併,當歸並長度爲2時,有n-1個狀態;
當歸並長度爲3時,有n-2個狀態;
當歸並長度爲n時,有1個狀態。
決策:當歸並長度爲2時,有1個決策;當歸並長度爲3時,有2個決策;
當歸並長度爲n時,有n-1個決策。
歸併長度len,起點i和決策點k三層循環,複雜度O(n^3),n<=1000肯定TLE。
四邊形不等式優化DP:
優化k!!! (k是i···j的分割點)
原來我是從i···j-1枚舉k, 取f(i,j)=min{f[i,k]+f[k+1,j]}+sum(i,j);
而實際上我只需要從s[i,j-1]到s[i+1,j]枚舉k就可以了。其中s[i,j]指f[i...j]取最優解的分割點,這樣複雜度就變成O(n^2).
PS:四邊形不等式優化DP,讀者可以閱讀:華中師大一附中 趙爽《動態規劃加速原理之四邊形不等式》。
環形石子歸併:
本題目屬於環形石子歸併類型,可以令n乘以2模擬環;亦可以取模運算。最後枚舉判斷環的起點(終點=起點+n-1),得到最小代價。
【代碼】
-
#include <cstdio>
-
#define inf 0xfffffff
-
#define maxn 2005
-
typedef int Arr[maxn][maxn];
-
int a[maxn],n,ans;
-
Arr sum,f,S;
-
int main()
-
{
-
int i,j,k,t;
-
while(~scanf("%d", &n)) {
-
for(i=1;i<=n;i++){
-
scanf("%d",&a[i]);
-
sum[i][i]=sum[i+n][i+n]=a[i+n]=a[i];
-
f[i][i]=f[i+n][i+n]=0;
-
}
-
for(i=1;i<=2*n;i++){
-
S[i][i]=i;
-
for(j=i+1;j<=i+n&&j<=2*n;j++)
-
sum[i][j]=sum[i][j-1]+a[j];
-
}
-
for(k=2;k<=n;k++){
-
for(i=1;i<=2*n-k+1;++i){
-
j=i+k-1;
-
f[i][j]=inf;
-
for(t=S[i+1][j];t>=S[i][j-1];--t){
-
if(f[i][j]>sum[i][j]+f[i][t]+f[t+1][j]){
-
f[i][j]=sum[i][j]+f[i][t]+f[t+1][j];
-
S[i][j]=t;
-
}
-
}
-
}
-
}
-
ans=inf;
-
for(i=1;i<=n;i++)
-
if(f[i][i+n-1]<ans)
-
ans=f[i][i+n-1];
-
printf("%d/n",ans);
-
}
-
return 0;
-
}