1. 程式人生 > >nyoj 737 石子合併(一) 區間動規

nyoj 737 石子合併(一) 區間動規

描述
    有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過N-1次合併後成為一堆。求出總的代價最小值。
輸入
有多組測試資料,輸入到檔案結束。
每組測試資料第一行有一個整數n,表示有n堆石子。
接下來的一行有n(0< n <200)個數,分別表示這n堆石子的數目,用空格隔開
輸出
輸出總代價的最小值,佔單獨的一行
樣例輸入
3
1 2 3
7
13 7 8 16 21 4 18
樣例輸出
9
239
來源
經典問題
上傳者
TC_胡仁東

ps: 區間dp。。。本題需要寫兩個狀態,,分別是每一個區間的和,也是上一局的總花費精力。。另一個需要的就是dp狀態轉移方程。。

這一局需要三層for迴圈。。第三層的作用是分割區間。

  例如:1 2 3 4 可以分為:

            1   234

            12   34

            123   4

本題i依然為區間長度,j為起始區間

程式碼如下:

#include<stdio.h>
#include<string.h>
const int inf=1000000;
int d[220][220],w[220][220];
int a[220];
int minn(int a,int b)
{
    return a<b?a:b;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(d,inf,sizeof(d));
        memset(w,0,sizeof(w));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
             w[1][i]=a[i];
             d[1][i]=0;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                w[i][j]=w[i-1][j]+w[1][i+j-1];
                //printf("##%d\n",w[i][j]);
            }
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=n-i+1;j++)
            {
                for(int k=1;k<i;k++)
                {
                   d[i][j]=minn(d[k][j]+d[i-k][k+j],d[i][j]);

                }
                d[i][j]+=w[i][j];
                //printf("###%d %d\n",d[i][j],w[i][j]);
            }
        }
        printf("%d\n",d[n][1]);

    }
}