您的位置:首页 > 其它

石子合并[DP-N3]

2016-08-31 15:18 225 查看

题目描述

在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

输入输出格式

输入格式:

数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

输出格式:

输出共2行,第1行为最小得分,第2行为最大得分.

--------------------------------------------------------

环形DP,前缀和,O(n3)即可

可以i降序j升序,也可以枚举长度

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=105<<2,INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a
,mx=0,mn=INF;
int f

,s
,d

;
void dp(){
for(int i=1;i<=2*n;i++)for(int j=1;j<=2*n;j++) d[i][j]=INF,d[i][i]=0;

for(int i=1;i<=2*n;i++) s[i]=s[i-1]+a[i];
//    for(int i=2*n-1;i>=1;i--)
//        for(int j=i+1;j<=2*n&&j-i<n;j++)
//            for(int k=i;k<j;k++){
//                f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
//                d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]+s[j]-s[i-1]);
//            }
for(int l=1;l<n;l++)
for(int i=1;i<=2*n;i++){
int j=min(2*n,i+l);
for(int k=i;k<j;k++){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]+s[j]-s[i-1]);
}
}

}
int main(int argc, const char * argv[]) {
n=read();
for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i];
dp();
for(int i=1;i<=n;i++) mx=max(f[i][i+n-1],mx),mn=min(mn,d[i][i+n-1]);
printf("%d\n%d",mn,mx);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: