(动态规划)2989:糖果

描述

由于在维护世界和平的事务中做出巨大贡献,Dzx被赠予糖果公司2010年5月23日当天无限量糖果免费优惠券。在这一天,Dzx可以从糖果公司的N件产品中任意选择若干件带回家享用。糖果公司的N件产品每件都包含数量不同的糖果。Dzx希望他选择的产品包含的糖果总数是K的整数倍,这样他才能平均地将糖果分给帮助他维护世界和平的伙伴们。当然,在满足这一条件的基础上,糖果总数越多越好。Dzx最多能带走多少糖果呢?
注意:Dzx只能将糖果公司的产品整件带走。

输入

第一行包含两个整数N(1<=N<=100)和K(1<=K<=100)
以下N行每行1个整数,表示糖果公司该件产品中包含的糖果数目,不超过1000000

输出

符合要求的最多能达到的糖果总数,如果不能达到K的倍数这一要求,输出0

样例输入

5 7

1

2

3

4

5

样例输出

14

 

我の思路

由于我比较笨(( ﹁ ﹁ ) ~→),所以借鉴了一下小哥的代码(传送门:http://blog.csdn.net/wx_t91/article/details/52713882)。

由于传统的01背包需要有一个容量,但是这个题里面只有物品,好像找不到容量,所以我们就要找到一个子问题去让他有一个容量。

我们发现:要达到被k整除,如果数字的余数加起来是k,那么这数字加起来就能被k整除。

所以我们把背包容量定义为k,找出数字余数加起来是k的组合。于是就得到f[i][j-num[i]%k],但是这样可能会有负数,于是我们再加一个k再整体进行%k,就可以正确取到余数。

另外还有一点注意的就是,对dp数组进行初始化的时候,给一个比0小的数字,如果赋予0,会导致答案错误(直接采取了方法避免分情况来赋值,在i=1的时候会误取到另外一个)。

补充:memset

memset(void *s, int ch,size_tn);中key实际范围应该在0~~255,因为该函数只能取ch的后八位赋值给你所输入的范围的每个字节,比如int a[5]赋值memset(a,-1,sizeof(int )*5)与memset(a,511,sizeof(int )*5) 所赋值的结果是一样的都为-1;因为-1的二进制码为(11111111 11111111 11111111 11111111)而511的二进制码为(00000000 00000000 00000001 11111111)后八位都为(11111111),所以数组中每个字节,如a[0]含四个字节都被赋值为(11111111),其结果为a[0](11111111 11111111 11111111 11111111),及a[0]=-1,因此无论ch多大只有后八位二进制有效,而八位二进制[2]  的范围(0~255)YKQ改。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为ASCII[3]  码。

 

我の代码

#include <iostream>
#include <algorithm>
#include<string.h>
int num[101];
int dp[101][101];
using namespace std;

int main()
{
    int n;
    int k;
    cin>>n>>k;

    memset(dp,-20,sizeof(dp));

    for(int i=1;i<=n;i++){
        cin>>num[i];
    }

    for(int i=0;i<=n;i++)
    {
        dp[i][0]=0;
    }


    for(int i=1;i<=n;i++){
       for(int j=0;j<=k;j++){
            dp[i][j] = max(dp[i-1][j],dp[i-1][(j+k-num[i]%k)%k]+num[i]);
       }
    }

    cout<<dp[n][0]<<endl;

    return 0;
}

 

posted @ 2017-09-12 21:39  章鱼小年糕  阅读(696)  评论(0编辑  收藏  举报