石子合併問題--圓形版(區間DP)

石子合併問題十分常見,典型的區間DP。這裏作爲一類問題整理出來,而沒有貼上題目。


dp[ i ][ j ]表示將區間[ i , j ]內的石子合併的最優解。同直線版的石子合併,當添加新的石堆時,枚舉所有的中間點分兩次合併,取最優解。需要注意的是,我們需要將圓形的石子合併問題轉變爲直線,可以將前部分的石子堆往後依次添加,這樣當做直線來處理。


代碼:

#include<cstdio>
#include<cstdlib>
using namespace std;

int a[110];
int n;
int min_ans;
int max_ans;
int sum(int c,int b)
{
    int total=0;
    for (int i=c; i<c+b; i++)
    {
        total=total+a[i%n];
    }
    return total;
}
void Merge()
{
    int min_dp[110][110];
    int max_dp[110][110];
    for(int i=0; i<n; i++)
    {
        min_dp[i][1]=0;
        max_dp[i][1]=0;
    }
    for(int i=2; i<=n; i++)
    {
        int temp1,temp2;
        for(int j=0; j<n; j++)
        {
            min_dp[j][i]=min_dp[j][1]+min_dp[(j+1)%n][i-1];
            max_dp[j][i]=max_dp[j][1]+max_dp[(j+1)%n][i-1];
            for(int k=2; k<i; k++)
            {
                temp1=min_dp[j][k]+min_dp[(j+k)%n][i-k];
                if(temp1 < min_dp[j][i])
                    min_dp[j][i] = temp1;
                temp2=max_dp[j][k]+max_dp[(j+k)%n][i-k];
                if(temp2 > max_dp[j][i])
                    max_dp[j][i] = temp2;
            }
            int sums=sum(j,i);
            min_dp[j][i]+=sums;
            max_dp[j][i]+=sums;
        }
    }
    min_ans=0x3f3f3f3f;
    max_ans=-1;
    for (int i=0; i<n; i++)
    {
        if (min_ans>min_dp[i][n])
            min_ans=min_dp[i][n];
        if (max_ans<max_dp[i][n])
            max_ans=max_dp[i][n];
    }
    return;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
        }
        Merge();
        printf("%d %d\n",min_ans,max_ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章