• NC50493 环形石子合并


    状态表示:\(f(i,j)\):从下标\(i\)合并到下标\(j\)的最大价值。

    先看石子合并(\(n\)堆石子):

    \[1,2,...,n \]

    \(f(1,n)\)即为答案。

    再看环形:

    最后的答案为:\(f(1,n)(f(n,1)和f(1,n)结果相同),f(2,1),f(3,2),...,\)中的最小值。

    我们当然不能在环上直接\(DP\),因为这样\(f(2,1),f(3,2)\)的合并结果不一定构成环形,可能是直接将相邻的两堆合并来得到\(f(2,1),f(2,3)\)的值。

    于是,破环成链应运而生!

    将石子\(1~n\)复制一遍,得到:

    \[1,2,...,n,1,2,...,n \]

    参考石子合并,我们可以得到\(f(1,n),f(2,1),...,f(n,n-1)\)的值,最后在它们中取最优值即可。

    const int N=410;//两倍空间
    int f[N][N];//min
    int g[N][N];//max
    int a[N<<1];
    int sum[N<<1];
    int n;
    
    int main()
    {
        cin>>n;
    
        for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
    
        for(int i=1;i<=n*2;i++) sum[i]=sum[i-1]+a[i];
    
        memset(f,0x3f,sizeof f);
    
        for(int i=n*2;i>=1;i--)
            for(int j=i;j<=n*2;j++)
            {
                if(i == j) f[i][j]=g[i][j]=0;
                else
                    for(int k=i;k<j;k++)
                    {
                        f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
                        g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]+sum[j]-sum[i-1]);
                    }
            }
    
        int resf=INF,resg=0;
        for(int i=1;i<=n;i++)
        {
            resf=min(resf,f[i][i+n-1]);
            resg=max(resg,g[i][i+n-1]);
        }
        cout<<resf<<endl;
        cout<<resg<<endl;
    
        //system("pause");
    }
    
  • 相关阅读:
    爱的感悟
    连点成图:享受创建图形的乐趣
    python实现动态更新远程机器列表的SSH登录脚本
    python生成数据库中所有表的DESC描述
    生活之美
    克服“测试怠惰”的习惯
    使用git和github托管个人项目
    连点成线
    一次合并数据库的经历
    python使用装饰器捕获异常
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14142453.html
Copyright © 2020-2023  润新知