描述
由于在维护世界和平的事务中做出巨大贡献,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; }