背包问题有很多种,常见的有01背包,完全背包,多重背包等,这里简单介绍几种,详细的可参考dd_engi大牛的背包九讲
01背包:n件物品放入容量为v的背包,每件物品只有一件,只可以选择放或是不放,求最大价值
模板
void zeroonepack(int cost,int value)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+value);
}
HDU-2602-Bone Collector
http://acm.hdu.edu.cn/showproblem.php?pid=2602
基本的01背包,套模板即可
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum;
int dp[1005];
int max(int x,int y)
{
return x>y?x:y;
}
void zeroonepack(int cost,int value)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+value);
}
int main()
{
int i,t,n;
int a[1005][2];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&sum);
for(i=0;i<n;i++)
scanf("%d",&a[i][0]);
for(i=0;i<n;i++)
scanf("%d",&a[i][1]);
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
zeroonepack(a[i][1],a[i][0]);
printf("%d\n",dp[sum]);
}
return 0;
}
HDU-2546-饭卡
http://acm.hdu.edu.cn/showproblem.php?pid=2546
这题很有意思,先用贪心,再做01背包
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum;
int dp[1005],price[1005];
int max(int x,int y)
{
return x>y?x:y;
}
void zeroonepack(int cost,int value)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+value);
}
int main()
{
int i,n,temp,k,m;
while(scanf("%d",&n),n)
{
temp=-1;
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
{
scanf("%d",&price[i]);
if(price[i]>temp)
{
temp=price[i];
k=i;
}
}
scanf("%d",&m);
if(m<5)
{
printf("%d\n",m);
continue;
}
sum=m-5; //5元去买价格最大的菜
for(i=0;i<n;i++) //剩下的做01背包
if(i!=k)
zeroonepack(price[i],price[i]);
printf("%d\n",m-price[k]-dp[sum]);
}
return 0;
}
完全背包:n件物品放入容量为v的背包,每种物品有无限件,求最大价值
模板
void completepack(int cost,int value)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+value);
}
HDU-1248-寒冰王座
http://acm.hdu.edu.cn/showproblem.php?pid=1248
基本的完全背包
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum,dp[10005];
int max(int x,int y)
{
return x>y?x:y;
}
void completepack(int cost,int value)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+value);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&sum);
memset(dp,0,sizeof(dp));
completepack(150,150);
completepack(200,200);
completepack(300,300);
printf("%d\n",sum-dp[sum]);
}
return 0;
}
HDU-1963-Investment
http://acm.hdu.edu.cn/showproblem.php?pid=1963
这题也是完全背包,需要注意的是背包的容量在发生变化,The value of a bond isalways a multiple of $1 000,这句话是关键,投资的成本是1000的倍数,本金和成本都除以1000可大大减少循环次数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum,dp[100001];
int max(int x,int y)
{
return x>y?x:y;
}
void completepack(int cost,int value)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+value);
}
int main()
{
int i,n,t,year,money;
int a[15][2];
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&money,&year,&n);
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i][0],&a[i][1]);
a[i][0]/=1000;
}
while(year--)
{
sum=money/1000;
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
completepack(a[i][0],a[i][1]);
money+=dp[sum];
}
printf("%d\n",money);
}
return 0;
}
多重背包:n件物品放入容量为v的背包,每件物品的件数都是有上限的,求最大价值
模板
void multiplepack(int cost,int value,int amount)
{
int k=1;
if(cost*amount>=sum)
completepack(cost,value);
else
{
while(k<amount)
{
zeroonepack(k*cost,k*value);
amount-=k;
k*=2;
}
zeroonepack(amount*cost,amount*value);
}
}
HDU-2191-珍惜现在,感恩生活
http://acm.hdu.edu.cn/showproblem.php?pid=2191
基本的多重背包
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum;
int dp[101];
int max(int x,int y)
{
return x>y?x:y;
}
void zeroonepack(int cost,int value)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+value);
}
void completepack(int cost,int value)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+value);
}
void multiplepack(int cost,int value,int amount)
{
int k=1;
if(cost*amount>=sum)
completepack(cost,value);
else
{
while(k<amount)
{
zeroonepack(k*cost,k*value);
amount-=k;
k*=2;
}
zeroonepack(amount*cost,amount*value);
}
}
int main()
{
int t;
int n,a,b,c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&sum,&n);
memset(dp,0,sizeof(dp));
while(n--)
{
scanf("%d%d%d",&a,&b,&c);
multiplepack(a,b,c);
}
printf("%d\n",dp[sum]);
}
return 0;
}
POJ-1014-Dividing
http://poj.org/problem?id=1014
这题也是多重背包,要想均分,只要一半容量的背包最大能容下一半的价值即可
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int sum,dp[60005];
int max(int x,int y)
{
return x>y?x:y;
}
void zeroonepack(int cost,int value)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+value);
}
void completepack(int cost,int value)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+value);
}
void multiplepack(int cost,int value,int amount)
{
int k=1;
if(cost*amount>=sum)
completepack(cost,value);
else
{
while(k<amount)
{
zeroonepack(k*cost,k*value);
amount-=k;
k*=2;
}
zeroonepack(cost*amount,value*amount);
}
}
int main()
{
int i,cases=1;
int num[6];
while(scanf("%d%d%d%d%d%d",&num[0],&num[1],&num[2],&num[3],&num[4],&num[5]))
{
if(num[0]==0&&num[1]==0&&num[2]==0&&num[3]==0&&num[4]==0&&num[5]==0)
break;
sum=0;
for(i=0;i<6;i++)
sum+=(i+1)*num[i];
printf("Collection #%d:\n",cases++);
if(sum&1) //若sum为奇数,一定不能均分
{
printf("Can't be divided.\n\n");
continue;
}
sum>>=1;
memset(dp,0,sizeof(dp));
for(i=0;i<6;i++)
if(num[i]!=0)
multiplepack(i+1,i+1,num[i]);
if(dp[sum]==sum)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}