zoukankan      html  css  js  c++  java
  • bzoj4247挂饰——压缩的动态规划

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4247

    1.dp之前要先按挂钩个数从大到小排序,不然挂钩一度用成负的也可能是正确的,不仅脚标难存,而且不知道各种时刻负多少以内是合法的。

    2.但是最多有4000000个挂钩,省掉一维勉强开下数组也就罢了,会TLE!

      考虑多余n=2000个的挂钩就不会被用上了,所以第二维开成2000;

      (——状态表示至少有 j 个挂钩!!!)

      那么当a [ i ] > j 的时候怎么办呢?大家都是这么写的:

      d [ i ] [ j ] = max( d [ i -1 ] [ j ] , d [ i - 1 ] [ max( j - a [ i ] , 0) +1 ] + b [ i ] );

      也就是若a [ i ] > j,则d [ i ] [ j ] = max( d [ i -1 ] [ j ] , d [ i - 1 ] [ 1 ] + b [ i ] ),然后把多出来的挂钩忽略;

      为什么一定是1而不是k(1<=k<=j)呢?因为d [ ] [ 1 ]一定是最大的值!

      这是因为d [ ] [ 1 ]其实可能有很多挂钩,但把多余挂钩都忽略了,所以记录的其实是所有剩余挂钩中的最大值;

      那么0也是啊?

        但0的话不能再挂东西了,而只要剩下1个挂钩,就可以往上挂下一个东西,所以1可以一直被更新;

      如果剩下的东西都是0挂钩怎么办?

        所以才不能只记录d [ ] [ 1 ],而要记录到n,这样该挂饰实际有多个挂钩的优势也不会被忽略了!

    3.所以到最后1表示有剩余挂钩的最大值,0表示无剩余挂钩的最大值;

      但其实每次都会用1的值更新0的值,所以最后直接输出0的值就行了!也就是像状态定义的一样,0包含了所有情况。

    4.突然想到,那么即使当 j - a [ i ] > 0,也不一定用 d [ i -1 ] [ j - a [ i ] ]来更新,只需用 k ( j - a [ i ] <= k <= j )然后忽略多余挂钩就行了;

      那为什么不这样呢?因为 j 的值越大,相当于对挂钩数的限制越严,卡掉的状态也越多,值就越来越不优了!

      所以尽量用靠前的 j 值来更新!

    5.所以应该是n^2的复杂度才对,为什么是约6000ms?而且那种省掉一维的写法为什么不行?

    updt(2018.9.18):当j==0时max(j-r[i].a,0)+1==1,会用到本层的值,应该用上一层的值。

            折中的方法是滚动数组。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n;
    long long d[2005],ans;
    struct Node{
        int a,c;
    }r[2005];
    bool cmp(Node x,Node y){return x.a>y.a;}
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&r[i].a,&r[i].c);
        sort(r+1,r+n+1,cmp);
        memset(d,-2,sizeof d);
        d[1]=0;
        for(int i=1;i<=n;i++)
        {
    //        printf("i=%d a[i]=%d c[i]=%d
    ",i,r[i].a,r[i].c);
    //        lm+=r[i].a;
            if(!r[i].a)//
                for(int j=0;j<=n;j++)
                    d[j]=max(d[j],d[j+1]+r[i].c);
            else for(int j=n;j>=0;j--)
                d[j]=max(d[j],d[max(j-r[i].a,0)+1]+r[i].c);
        }
        ans=-2e9-7;
        for(int i=0;i<=n;i++)//i=0
            ans=max(ans,d[i]);
        printf("%lld",ans);
        return 0;
    }
    省掉一维的WA
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n;
    long long d[2005][2005],ans;
    struct Node{
        int a,c;
    }r[2005];
    bool cmp(Node x,Node y){return x.a>y.a;}
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&r[i].a,&r[i].c);
        sort(r+1,r+n+1,cmp);
        memset(d,-2,sizeof d);
        d[0][1]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
                d[i][j]=max(d[i-1][j],d[i-1][max(j-r[i].a,0)+1]+r[i].c);
        }
    //    ans=-2e9-7;
    //        for(int i=0;i<=n;i++)//i=0
    //            ans=max(ans,d[n][i]);
    //    ans=max(d[n][0],d[n][1]);
        printf("%lld",d[n][0]);
        return 0;
    }
  • 相关阅读:
    tar命令,vi编辑器
    Linux命令、权限
    Color Transfer between Images code实现
    利用Eclipse使用Java OpenCV(Using OpenCV Java with Eclipse)
    Matrix Factorization SVD 矩阵分解
    ZOJ Problem Set
    Machine Learning
    ZOJ Problem Set
    ZOJ Problem Set
    ZOJ Problem Set
  • 原文地址:https://www.cnblogs.com/Narh/p/8724197.html
Copyright © 2011-2022 走看看