zoukankan      html  css  js  c++  java
  • NC51170 石子合并

    经典的区间\(DP\)问题。

    区间\(DP\)特征:从小区间逐渐向大区间扩展递推。

    题解

    贪心只能处理“任取两堆”,而不能处理“相邻两堆”。任取两堆的题目就是合并果子

    状态表示:\(f(i,j)\):合并区间\([i,j]\)的最小代价
    状态转移:\(f(i,j) = \begin{cases}0,i = j\\ \underset{i≤k<j}{min}(f(i,j),f(i,k)+f(k+1,j)+sum(i,j)),i≠j \end{cases}\)
    \(sum(i,j)\)为区间\([i,j]\)内石子的个数。

    相当于将\([i,j]\)拆成两个区间\([i,k]\)\([k+1,j]\),两个区间各自合并石子需要\(f(i,k)\)
    \(f(k+1,j)\)的代价,将两个区间合并需要\(sum(i,j)\)的代价。

    \(\color{red}{Wrong Answer}\)代码:

    const int N=310;
    int f[N][N];
    int a[N];
    int sum[N];
    int n;
     
    int main()
    {
        cin>>n;
     
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum[i]=sum[i-1]+a[i];
        }
     
        memset(f,0x3f,sizeof f);
     
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
            {
                if(i == j) f[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]);
            }
     
        cout<<f[1][n]<<endl;
        //system("pause");
    }
    

    在考虑如何递推时,应考虑如下几个方面:

    • 是否能覆盖全部状态?
    • 求解后面状态时是否保证前面状态已经确定?
    • 是否修改了已经确定的状态?

    也就是说,在考虑递推顺序时,务必参考动态规划的对象具有的性质。

    既然之前说过我们需要枚举k来划分i和j,那么如果通过枚举i和j进行状态转移,很显然某些k值时并不能保证已经确定过所需状态。

    • \(i=1 ~ 10\)
    • \(j=1 ~ 10\)
    • \(k=1 ~ 9\)

    \(i=1,j=5,k=3\)时,显然状态\(f(k+1,j)\)没有计算。

    解决办法也很简单,将\(i\)倒序循环即可。
    \(\color{green}{Accepted}\)代码:

    const int N=310;
    int f[N][N];
    int a[N];
    int sum[N];
    int n;
    
    int main()
    {
        cin>>n;
    
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum[i]=sum[i-1]+a[i];
        }
    
        memset(f,0x3f,sizeof f);
    
        for(int i=n;i>=1;i--)
            for(int j=i;j<=n;j++)
            {
                if(i == j) f[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]);
            }
    
        cout<<f[1][n]<<endl;
        //system("pause");
    }
    
  • 相关阅读:
    分布式缓存Redis的集群-主从复制
    搭建私有Nuget服务
    分布式缓存Redis的持久化方式RDB和AOF
    .Net Core使用分布式缓存Redis:Lua脚本
    .Net Core使用分布式缓存Redis:数据结构
    .Net Core使用分布式缓存Redis:基础
    Android基础开发归档
    gdb 调试
    linux shell 常用表达式汇总
    V8 data struct
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14140857.html
Copyright © 2011-2022 走看看