HDU 3506 Monkey Party 【DP+四邊形不等式優化】

【題目地址】

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),得到最小代價。

【代碼】

隱藏行號 複製代碼 C/C++
  1. #include <cstdio>
    
  2. #define inf 0xfffffff
    
  3. #define maxn 2005
    
  4. typedef int Arr[maxn][maxn];
    
  5. int a[maxn],n,ans;
    
  6. Arr sum,f,S;
    
  7. int main()
    
  8. {
    
  9.     int i,j,k,t;
    
  10.     while(~scanf("%d", &n)) {
    
  11.         for(i=1;i<=n;i++){
    
  12.             scanf("%d",&a[i]);
    
  13.             sum[i][i]=sum[i+n][i+n]=a[i+n]=a[i];
    
  14.             f[i][i]=f[i+n][i+n]=0;
    
  15.         }
    
  16.         for(i=1;i<=2*n;i++){
    
  17.             S[i][i]=i;
    
  18.             for(j=i+1;j<=i+n&&j<=2*n;j++)
    
  19.                 sum[i][j]=sum[i][j-1]+a[j];
    
  20.         }
    
  21.         for(k=2;k<=n;k++){
    
  22.             for(i=1;i<=2*n-k+1;++i){
    
  23.                 j=i+k-1;
    
  24.                 f[i][j]=inf;
    
  25.                 for(t=S[i+1][j];t>=S[i][j-1];--t){
    
  26.                         if(f[i][j]>sum[i][j]+f[i][t]+f[t+1][j]){
    
  27.                             f[i][j]=sum[i][j]+f[i][t]+f[t+1][j];
    
  28.                             S[i][j]=t;
    
  29.                     }
    
  30.                 }
    
  31.             }
    
  32.         }
    
  33.         ans=inf;
    
  34.         for(i=1;i<=n;i++)
    
  35.             if(f[i][i+n-1]<ans)
    
  36.                 ans=f[i][i+n-1];
    
  37.         printf("%d/n",ans);
    
  38.     }
    
  39.     return 0;
    
  40. }
    
  41. 
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章