石子合并(区间)

描述
将 n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
选择一种合并石子的方案,使得做 n−1次合并得分总和最小。
输入
输入第一行一个整数 n,表示有 n 堆石子。
第二行 n 个整数,表示每堆石子的数量。
输出
输出共两行:
第一行为合并得分总和最小值,
第二行为合并得分总和最大值。
样例输入
4
4 5 9 4
样例输出
43
54
提示
对于 100% 的数据,有1≤n≤200

区间dp基础题啊

从长度从小往大枚举

然后枚举左端点

枚举中间点

取max就可以了

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
int n,f[405][405],g[405][405],a[405],sum[405];
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        a[i]=a[i+n]=read();
    }
    memset(f,127/3,sizeof(f));
    for(int i=1;i<=2*n;i++){
        sum[i]=sum[i-1]+a[i];
        f[i][i]=g[i][i]=0;
    }    
    for(int len=2;len<=2*n;len++){
        for(int l=1;l<=2*n-len+1;l++){
            if(l+len>2*n)break;
            int r=l+len-1;
            for(int k=l;k<=r;k++){
                f[l][r]=min(f[l][k]+f[k+1][r],f[l][r]);
                g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]);
            }
            f[l][r]+=(sum[r]-sum[l-1]);
            g[l][r]+=(sum[r]-sum[l-1]);
        }
    }
    int maxn=0,minn=1e9;
    for(int i=1;i<=n;i++){
        maxn=max(maxn,g[i][i+n-1]);
        minn=min(minn,f[i][i+n-1]);
    }
    cout<<minn<<'\n'<<maxn;
}
posted @ 2018-10-30 21:47  Stargazer_cykoi  阅读(133)  评论(0编辑  收藏  举报