Description
给定N种物品和一个容量为C的背包,第i种物品最多有 Mi 件可用,每件的重量是Wi,价值是Vi。问:将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
Input
输入的第一行为测试样例的个数T,接下来有T个测试样例。
每个测试样例的第一行是物品种数N(1 ≤ N ≤ 100)和背包容量C(C ≤ 10000)。
接下来N行,每行三个正整数,Wi ,Vi 和 Mi ( Wi ≤ 10000, Vi ≤ 10000, Mi ≤ 10000 ),分别表示第i种物品的重量 Wi ,价值 Vi ,及个数 Mi 。
Output
对应每个测试样例输出一行,只有一个整数,表示装入背包的物品总价值的最大值。
Sample Input
1
2 8
4 100 2
2 100 4
Sample Output
400
代码如下:
#include<cstdio>///oj1943
#include<algorithm>
#include<cstring>
using namespace std;
const int MAX=20000;
int dp[MAX],w[MAX],v[MAX];
int main()
{
int n,c,ncase;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d%d",&n,&c);
int weigh,value,times;
int sum=1;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&weigh,&value,×);
for(int j=1;j<=times;j<<=1)///二进制处理times,将一个背包分成多个(可取次数为1的)背包
{
w[sum]=j*weigh;
v[sum++]=j*value;
times-=j;
}
if(times>0){
w[sum]=times*weigh;
v[sum++]=times*value;
}
}
memset(dp,0,sizeof(dp));
for(int i=1;i<sum;i++)///这里的和01背包没什么区别
{
for(int j=c;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
printf("%d\n",dp[c]);
}
return 0;
}
这里还可用深搜解决:
#include<cstdio>///深搜
#include<algorithm>
#include<cstring>
using namespace std;
int num[7],flag,sum;
void dfs(int S,int tot)
{
if(S==sum){
flag=1;return;
}
if(flag==1) return;
for(int i=6;i>0;i--)///相当于枚举,从最后开始,假设num[i]有n个,那么会递归调用开辟n个空间,每个空间的S值为
{ ///从小到大i,2*i,3*i......k*i(1<=k<=n,k*i<=sum)),紧接着又在每个空间跟num[i-1]类似上面的递归调用
if(num[i]>=1){///在递归过程中只要S的值==sum,就一直返回就好了,很暴力
if(S+i<=sum) {
num[i]--;
dfs(S+i,i);
if(flag==1) return;
}
}
}
return;
}
int main()
{
int ncase=0;
while(1)
{
ncase++;
sum=0;
for(int i=1;i<=6;i++){
scanf("%d",&num[i]);
sum+=num[i]*i;
}
if(sum==0) break;
printf("Collection #%d:\n",ncase);
if(sum%2){
printf("Can't be divided.\n\n");continue;
}
sum/=2;///注意除以2
flag=0;
dfs(0,6);
if(flag) printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
return 0;
}