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;
}