zoukankan      html  css  js  c++  java
  • cf 366C C. Dima and Salad(01背包)

    http://codeforces.com/contest/366/problem/C

    题意:给出n个水果的两种属性a属性和b属性,然后挑选苹果,选择的苹果必须要满足这样一个条件:,现在给出n,k,要你求满足这种条件的苹果a属性之和最大,如果找不到,输出-1.

    思路:是dp题目,倒是给我提醒比较大。这个题目是可以转化的,转为  所有(aj-k*bj)之和,然后对于任意一个苹果,就是挑与不挑的关系,很明显的背包问题。

    对于任意一个苹果,如果选择它,则是dp[v-(aj-k*bj)]+aj,不选择它,就是dp[j]自己本身.......额,好像很简单的样子,其实这样是错的。因为(aj-k*bj)可以是负数,那么这样转移就不对,因为有的状态数无法表示出来,比如说,当(aj-k*bj)==-5,那么对于dp[-1]这个状态可以从dp[4]转移过去,而实际上,dp[-1]是不合法的数组.....

    如此来说,我想到的解决方法就是平移10000个单位,因为n,a[i],b[i]最大都是100,所以只需要平移10000个单位,当然为了不出现其他边界问题,我是平移了15000个单位,然后一遍背包过去,发现还是错的.......

    回到题目所给出的公式,,转化过来,应该这样表述才是对的, 从(0——j)的(aj-k*bj)之和==0,实质上,转化为背包来做,这个题目的体积并没有固定,不是吗?但是从(0——j)的(aj-k*bj)之和==0这里却是给出了。若没有平移单位,那么最终值是dp[0]的值,这里平移了15000个单位,那么最终所求问题却应该是dp[15000],并且,是要将15000这个容量恰好装满,如此,似乎这道题目有解了,但是wa在第六组测试数据;

    第一次wa代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[40005];
    int s[205][2];
    int main()
    {
        int n,k;
        while(scanf("%d%d",&n,&k)>0)
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][0]);
            }
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][1]);
            }
            memset(dp,-1,sizeof(dp));
            //for(int i=0;i<=n;i++)
            //for(int j=0;j<=30000;j++)
            //dp[j]=-(1<<31);
            //printf("%d  ",dp[i][j]);
            int m=15000;
            dp[m]=0;
            for(int i=1; i<=n; i++)
            {
                int b=s[i][0]-k*s[i][1];
                //printf("%d
    ",b);
                for(int j=2*m; j>=0; j--)
                {
                    if(j-b>=0&&j-b<=2*m&&dp[j-b]!=-1)
                    {
                        if(dp[j-b]+s[i][0]>dp[j])
                        dp[j]=dp[j-b]+s[i][0];
                    }
    
                }
            }
            if(dp[m]==0)
                printf("-1
    ");
            else
                printf("%d
    ",dp[m]);
        }
        return 0;
    }
    

     为什么会wa?想了很久,考虑到一个问题,对于dp[40000]这个数组,我只是将第一层置为-1,会不会在n层之后,会有这么一个现象,对于当前第n层,dp[j]!=-1,但实际上,dp[n][j]却是应该==-1的,也就是说,由于只是开了一维数组,我所需要的第n层数据被前面的值覆盖掉了.......这是很有可能的,出于小心,我把代码改为了二维数组,如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[215][40005];
    int s[205][2];
    int main()
    {
        int n,k;
        while(scanf("%d%d",&n,&k)>0)
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][0]);
            }
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][1]);
            }
            memset(dp,-1,sizeof(dp));
            //for(int i=0;i<=n;i++)
            //for(int j=0;j<=30000;j++)
            //dp[i][j]=-(1<<31);
            //printf("%d  ",dp[i][j]);
            int m=15000;
            dp[0][m]=0;
            for(int i=1; i<=n; i++)
            {
                int b=s[i][0]-k*s[i][1];
                //printf("%d
    ",b);
                for(int j=2*m; j>=0; j--)
                {
                    if(j-b>=0&&j-b<=2*m&&dp[i-1][j-b]!=-1)
                    {
                        if(dp[i-1][j-b]+s[i][0]>dp[i-1][j])
                        dp[i][j]=dp[i-1][j-b]+s[i][0];
                        else
                        dp[i][j]=dp[i-1][j];
                    }
    
                }
            }
            int maxn=-10;
            for(int i=0;i<=n;i++)
            if(dp[i][m]>maxn)
            maxn=dp[i][m];
            if(maxn==0)
                printf("-1
    ");
            else
                printf("%d
    ",maxn);
        }
        return 0;
    }
    

     额,继续wa在第六组测试数据......心中千万只草泥马飞奔而过......我思路没错啊,代码检查了好几次,好像也没什么问题......纠结许久,想着,会不会是我将所有值置为-1那里出现问题了?一般来说,要是恰好那么多容量的话,都是置为负无穷大,可是我用-1来标记负无穷大也没错啊,以前都是这样做的,没出什么问题......抱着试试的心态,改了下代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[215][40005];
    int s[205][2];
    int main()
    {
        int n,k;
        while(scanf("%d%d",&n,&k)>0)
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][0]);
            }
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&s[i][1]);
            }
            //memset(dp,-1,sizeof(dp));
            for(int i=0;i<=n;i++)
            for(int j=0;j<=30000;j++)
            dp[i][j]=-(1<<31);
            //printf("%d  ",dp[i][j]);
            int m=15000;
            dp[0][m]=0;
            for(int i=1; i<=n; i++)
            {
                int b=s[i][0]-k*s[i][1];
                //printf("%d
    ",b);
                for(int j=2*m; j>=0; j--)
                {
                    if(j-b>=0&&j-b<=2*m)
                    {
                        if(dp[i-1][j-b]+s[i][0]>dp[i-1][j])
                        dp[i][j]=dp[i-1][j-b]+s[i][0];
                        else
                        dp[i][j]=dp[i-1][j];
                    }
    
                }
            }
            //int maxn=-10;
            //for(int i=1;i<=n;i++)
            //if(dp[i][m]>maxn)
            //maxn=dp[i][m];
            if(dp[n][m]==0)
                printf("-1
    ");
            else
                printf("%d
    ",dp[n][m]);
        }
        return 0;
    }
    

     惊现ac..........可是,可是,我想的是这代码是不能ac的啊.....能不能靠谱点?决定了,以后对于这样要恰好的容积,都置为负无穷大。

    但是我对于这代码想了许久,还是不知道为什么我把dp内所有值置为-1,会错......若有朋友路过,看到,请赐教.......,谢谢.......

  • 相关阅读:
    [WC2010]重建计划
    [POJ1741]Tree
    [NOI2008]志愿者招募
    [BZOJ2127]happiness
    「网络流 24 题」太空飞行计划
    [TJOI2015]线性代数
    [HDU2874]Connections between cities
    [POI2007]ZAP-Queries
    [SCOI2010]幸运数字
    POJ 2826 An Easy Problem?!
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/3442142.html
Copyright © 2011-2022 走看看