背包问题

背包问题有很多种,常见的有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;
}












  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值