这道题的题目描述好混乱的说,但是读明白了就能看出来,实际上这道题是一个多重背包,但是,就那么写多重背包必然会超时,所以就有了一个优化,多重背包二进制拆分优化。《背包九讲》中介绍过这种优化,但是昨天看了好久,没明白原理,所以求助+YY,总算是了解了。。所谓二进制拆分优化,就是把n[i]个物品给拆分,每个物品占的空间是c[i],c[i]*2,c[i]*22,c[i]*23...c[i]*2k-1,c[i]*(n[i]-2k+1),实际上加和以后还是(c[i]*n[i]),物品的价值也是这么拆分,为什么这么拆分呢?思路来自于二进制数表示法,比如说510=1012,也就是说如果取5件i物品,相当于取第一件和第三件(20+22)所有的数都可以这么表示出来,所以可以说这么拆分了以后和原来是等价的,所以这么拆分当然就是合理的。附AC代码: view code #include <iostream> #include <cstdio> #include <cstring> using namespace std; int max(int a, int b) { if (a > b) return a; else return b; } int main() { int cash, n, cc, c[100000], num[15], t, i, j, tot, dp[100005]; while ((scanf("%d%d", &cash, &n)) != EOF) { tot = 0; memset(c, 0, sizeof(c)); for (i = 1; i <= n; i++) { cin >> num[i] >> cc; if (num[i] != 0) { tot++; c[tot] = cc; num[i]--; } t = 2; while (num[i] >= t) { num[i] -= t; tot++; c[tot] = cc * t; t *= 2; } if (num[i] > 0) { tot++; c[tot] = num[i] * cc; } } memset(dp, 0, sizeof(dp)); for (i = 1; i <= tot; i++) for (j = cash; j >= c[i]; j--) { dp[j] = max(dp[j], dp[j - c[i]] + c[i]); } cout << dp[cash] << endl; } return 0; }
特别鸣谢:飞哥figo
|