石子合并问题--圆形版(区间dp)

在圆形操场上摆放着一行共n堆的石子。现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请编辑计算出将n堆石子合并成一堆的最小得分和将n堆石子合并成一堆的最大得分。Input输入有多组测试数据。

每组第一行为n(n<=100),表示有n堆石子,。

二行为n个用空格隔开的整数,依次表示这n堆石子的石子数量ai(0<ai<=100)

Output

每组测试数据输出有一行。输出将n堆石子合并成一堆的最小得分和将n堆石子合并成一堆的最大得分。 中间用空格分开。Sample Input3

1 2 3

Sample Output9 11

我写的是端点和区间长度式的。

 

环形主要处理的是,如何确定断点,使环形变成我们熟知的线性。所以采用了断环为链的手法。

将环形断开然后将其复制一条,在接上。

如下:

3

1 2 3

变成:

1 2 3 1 2 3

 

代码如下:

 

#include<iostream>
#define min(a,b)  (a)<(b)?(a):(b)
#define max(a,b)  (a)>(b)?(a):(b)
#define IFN 0x3f3f3f
using namespace std;

int dp[210][210];       //将其复制为两个
int ff[210][210];
int num[105];
int sum[210];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>num[i];
    for(int i=1;i<=n+n;i++)
    sum[i]=sum[i-1]+num[(i-1)%n+1];

    for(int len=1;len<n;len++)
    {
        for(int i=1,j=len+i;j<=n+n;i++,j++)
        {
            dp[i][j]=IFN;
            for(int s=i;s<j;s++)
            {
                dp[i][j]=min(dp[i][j], dp[i][s]+dp[s+1][j]+sum[j]-sum[i-1]);
                ff[i][j]=max(ff[i][j], ff[i][s]+ff[s+1][j]+sum[j]-sum[i-1]);
            }
        }
    }
    int a=IFN;  int b=0;
    for(int i=1;i<=n;i++)
    {
        a=min(a, dp[i][i+n-1]);
        b=max(b, ff[i][i+n-1]);
    }
    cout<<a<<" "<<b<<endl;
    return 0;
}

posted @ 2018-06-03 21:16  神韵袖藏  阅读(956)  评论(0编辑  收藏  举报