HDU-CRB and His Birthday(动态规划本质未认清)---01背包与完全背包的结合!

This problem will be judged on  HDU. Original ID:  5410
64-bit integer IO format:  %I64d      Java class name:  Main
Type: 
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •                   
  • Today is CRB's birthday. His mom decided to buy many presents for her lovely son.
    She went to the nearest shop with  M  Won(currency unit).
    At the shop, there are  N  kinds of presents.
    It costs  Wi  Won to buy one present of  i -th kind. (So it costs  k  ×  Wi  Won to buy  k  of them.)
    But as the counter of the shop is her friend, the counter will give  Ai × x + Bi  candies if she buys  x ( x >0) presents of  i -th kind.
    She wants to receive maximum candies. Your task is to help her.
    1 ≤  T  ≤ 20
    1 ≤  M  ≤ 2000
    1 ≤  N  ≤ 1000
    0 ≤  Ai, Bi  ≤ 2000
    1 ≤  Wi  ≤ 2000

    Input

    There are multiple test cases. The first line of input contains an integer  T , indicating the number of test cases. For each test case:
    The first line contains two integers  M  and  N .
    Then  N  lines follow,  i -th line contains three space separated integers  Wi Ai  and  Bi .

    Output

    For each test case, output the maximum candies she can gain.

    Sample Input

    1
    100 2
    10 2 1
    20 1 1

    Sample Output

    21

    这道题我的思路是

    完全背包。还有就是另开一个数组记录这件物品拿过没

    如果拿过了,就不加B了如果没拿就加上B。

    上代码!别急着粘贴复制,因为这个代码是WA的!

    #include<stdio.h>
    #include<string.h>
    int a[2005],b[2005],w[2005];
    int dp[2005];
    bool vis[1005];
    int max(int a,int b)
    {
        if(a>b)
            return a;
        else
            return b;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int m,n,maxx=0;
            scanf("%d%d",&m,&n);
            for(int i=1; i<=n; i++)
            {
                scanf("%d%d%d",&w[i],&a[i],&b[i]);
            }
            memset(dp,0,sizeof(dp));
            memset(vis,false,sizeof(vis));
            for(int i=1; i<=n; i++)
            {
                for(int j=w[i]; j<=m; j++)
                {
                    //printf("*-*\n");
                    if(vis[i]==false)
                    {
                        if(dp[j-w[i]]+a[i]+b[i]>dp[j])
                        {
                            vis[i]=true;
                        }
                        //printf("%d\n",dp[j-w[i]]);
                        dp[j]=max(dp[j-w[i]]+a[i]+b[i],dp[j]);
                    }
                    else
                    {
                        dp[j]=max(dp[j-w[i]]+a[i],dp[j]);
                    }
                }
                /*for(int k=1;k<=m;k++)
                {
                    printf("%d ",dp[k]);
                }
                printf("\n");*/
            }
            for(int i=1; i<=m; i++)
            {
                if(dp[i]>maxx)
                {
                    maxx=dp[i];
                }
            }
            printf("%d\n",maxx);
        }
        return 0;
    }
    看完是不是觉得很有道理!是不是觉得WA的很没道理

    刚开始我也是这么觉得的!那是我没有牢记动态规划的本质!

    那么动态规划的本质是什么?

    动态规划其实是把所有可能的情况都考虑了一遍

    如果按上面想法,一件物品用一次,第二次只加A,那么我如何能考虑完全所有情况

    比如有三件物品

    第一次我拿了第一件,第一件标记一下,然后拿了第二件发现第二件更好,第一件放下,这时候第一件的标记也

    没有办法去掉了,所有综上,由于过程过于复杂,这样做是不行的

    所以有了新方法!

    先01背吧,每件物品一件,先求出最优解,再用完全背包每件物品多件(在以前的最优解的基础上)

    这样就没有问题了

    #include<stdio.h>
    #include<string.h>
    int a[2005],b[2005],w[2005];
    int dp[2005];
    bool vis[1005];
    int max(int a,int b)
    {
        if(a>b)
            return a;
        else
            return b;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int m,n,maxx=0;
            scanf("%d%d",&m,&n);
            for(int i=1; i<=n; i++)
            {
                scanf("%d%d%d",&w[i],&a[i],&b[i]);
            }
            memset(dp,0,sizeof(dp));
            memset(vis,false,sizeof(vis));
            for(int i=1; i<=n; i++)
            {
                for(int j=m; j>=w[i]; j--)
                {
                    dp[j]=max(dp[j],dp[j-w[i]]+a[i]+b[i]);
                }
                for(int k=w[i];k<=m;k++)
                {
                    dp[k]=max(dp[k],dp[k-w[i]]+a[i]);
                }
                /*for(int l=1;l<=m;l++)
                {
                    printf("%d ",dp[l]);
                }
                printf("\n");*/
            }
            for(int i=1; i<=m; i++)
            {
                if(dp[i]>maxx)
                {
                    maxx=dp[i];
                }
            }
            printf("%d\n",maxx);
        }
        return 0;
    }








    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值