1. 程式人生 > >【基礎演算法】石子合併-版本1

【基礎演算法】石子合併-版本1

此題主要是用dp求出每個範圍的最小价值,再用遞迴輸出。
時間限制: 1 Sec 記憶體限制: 64 MB
題目描述

設有n堆石子排成一排,其編號為1,2,3,…,n。每堆石子有一定的數量,例如: 13 7 8 16 21 4 18 現要將n堆石子歸併為一堆。歸併的過程為每次只能將相鄰的兩堆石子堆成一堆,這樣經過n-1次歸併之後最後成為一堆。對於上面的7堆石子,可以有多種方法歸併成一堆。其中的2種方法入下圖: 歸併的代價是這樣定義的:將兩堆石子歸併為一堆時,兩堆石子數量的和稱為歸併2堆石子的代價。如上圖中,將13和7歸併為一堆的代價為20。歸併的總代價指的是將沙子全部歸併為一堆沙子的代價的和。如上面的2種歸併方法中, 第1種的總代價為 20+24+25+44+69+87 = 267 第2種的總代價為 15+37+22+28+59+87 = 248 由此可見,不同歸併過程得到的總的歸併代價是不一樣的。 當n堆石子的數量給出後,找出一種合理的歸併方法,使總的歸併代價為最小。
輸入

第1行:1個整數n(1<=n<=100),表示石子的數量第
2行:n個用空格分開的整數,每個整數均小於10000,表示各堆石子的數量。
輸出

第1行:1個整數,表示最小的歸併代價

第2行:用括號表示的歸併順序。加括號的要求見樣例。如果只有1堆石子,輸出時不要加括號。

樣例輸入

3
13 7 8

樣例輸出

43
(13)((7)(8))

要用dp存入的話,就先得把每個範圍的的總價值搞清楚。(每個合併下的總值都不會超過總每個範圍的石頭數)
===>

scanf("%d",&n);
   for(int i=1;i<=n;i++)
    {
        scanf
("%d",&c[i]); w[i]=w[i-1]+c[i]; } //若要求i_j範圍內的總價值,即為w[j]-w[i-1](j>i)

然後為了便於dp先把長度定下來

for(int len=1;len<n;len++)

列舉起始點

for(int i=1;i+len<=n;i++)

然後列舉每一個端點(用於分割槽域)並存入座標。

for(int len=1;len<n;len++)
        for(int i=1;i+len<=n;i++)
        {
            int j=i+len
; t=INT_MAX; for(int k=i;k<j;k++) if(dp[i][k]+dp[k+1][j]<t) { pre[i][j]=k; t=dp[i][k]+dp[k+1][j]; } dp[i][j]=t+w[j]-w[i-1]; }

輸出

printf("%d\n",dp[1][n]);

然後用一個遞迴輸出(分範圍):

{
    if(i==j)
    {
        printf("%d",c[i]);
        return ;
    }
    printf("(");
    print(i,pre[i][j]);
    printf(")(");
    print(pre[i][j]+1,j);
    printf(")");
}

完整程式碼如下:

#include<cstdio>
#include<climits>
int n,c[105],w[105],dp[105][105],pre[105][105],t;
void print(int i,int j)
{
    if(i==j)
    {
        printf("%d",c[i]);
        return ;
    }
    printf("(");
    print(i,pre[i][j]);
    printf(")(");
    print(pre[i][j]+1,j);
    printf(")");
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        w[i]=w[i-1]+c[i];
    }
    for(int len=1;len<n;len++)
        for(int i=1;i+len<=n;i++)
        {
            int j=i+len;
            t=INT_MAX;
            for(int k=i;k<j;k++)
                if(dp[i][k]+dp[k+1][j]<t)
                {
                    pre[i][j]=k;
                    t=dp[i][k]+dp[k+1][j];
                }
            dp[i][j]=t+w[j]-w[i-1];
        }
    printf("%d\n",dp[1][n]);
    print(1,n);
}