http://acm.hdu.edu.cn/showproblem.php?pid=2844
也是多重背包问题。。
就是找出能拼成几种价格。。
就是一开始脑残用了一个标记数组,后来发现直接不需要,就遍历数组,当此时背包中能拿到最大的价值与背包此时的重量相等就加一种。if(dp[i] == i) count++;
一开始标记数组的代码:
#include<iostream> #include<cstring> int dp[100010]; int w[110]; int m[110]; bool mark[100010]; using namespace std; int main () { int n,v; while(cin >> n >> v && (n||v)) { memset(dp,0,sizeof(dp)); memset(mark,0,sizeof(mark)); for(int i = 1;i <= n;i++) cin >> w[i]; for(int i = 1;i <= n;i++) cin >> m[i]; for(int i = 1;i <= n;i++) { if(w[i]*m[i] >= v) { for(int j = w[i];j <= v;j++) { dp[j] = max(dp[j],dp[j-w[i]]+w[i]); mark[dp[j]] = 1; } } else { int k = 1; while(k < m[i]) { for(int j = v;j >= k*w[i];j--) { dp[j] = max(dp[j],dp[j-k*w[i]]+k*w[i]); mark[dp[j]] = 1; } m[i] = m[i]-k; k = 2*k; } for(int j = v;j >= m[i]*w[i];j--) { dp[j] = max(dp[j],dp[j-m[i]*w[i]]+m[i]*w[i]); mark[dp[j]] = 1; } } } int sum = 0; for(int i = 1;i <= v;i++) { if(mark[i]) sum += 1; } cout << sum << endl; } return 0; }舍去标记数组以后:
#include<iostream> #include<cstring> int dp[100010]; int c[110]; int m[110]; using namespace std; int main () { int n,v; while(cin >> n >> v && (n||v)) { memset(dp,0,sizeof(dp)); for(int i = 1;i <= n;i++) cin >> c[i]; for(int i = 1;i <= n;i++) cin >> m[i]; for(int i = 1;i <= n;i++) { if(c[i]*m[i] > v) { for(int j = c[i];j <= v;j++) dp[j] = max(dp[j],dp[j-c[i]]+c[i]); } else { int k = 1; while(k < m[i]) { for(int j = v;j >= k*c[i];j--) dp[j] = max(dp[j],dp[j-k*c[i]]+k*c[i]); m[i] -= k; k *= 2; } for(int j = v;j >= m[i]*c[i];j--) dp[j] = max(dp[j],dp[j-m[i]*c[i]]+m[i]*c[i]); } } int count = 0; for(int i = 1;i <= v;i++) { if(dp[i] == i) count++; } cout << count << endl; } return 0; }