01背包问题 NOJ 1308 POJ3624

    该题是纯粹的01背包问题。

    01背包算法的最优解具有最优子结构特性。对于任一件物品,它在最优解中存在两种情况,放入背包为1,不放入背包为0,最优解即为两者之中的较大者。因为加入此件物品耗费了载重量,所以存在不放入此件物品而放入单位收益较大的物品收益情况更大的情况。算法使用的是递归的形式,其执行过程是自下而上的,即一层层地递归至最底层,再根据dp方程,自下而上推导至最优解。在此不详细介绍了。

    话不多说,见题目:

背包问题

时间限制(普通/Java) :  1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 152            测试通过 : 38 

比赛描述

         试设计一个用回溯法搜索子集空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解0-1背包问题。

0-1 背包问题描述如下:给定n 种物品和一个背包。物品i 的重量是 wi ,其价值为 v i,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

在选择装入背包的物品时,对每种物品i只有2 种选择,即装入背包或不装入背包。不能将物品i 装入背包多次,也不能只装入部分的物品i。

0-1 背包问题形式化描述:给定C>0, Wi >0, Vi >0,1≤i≤n,要求n 元0-1向量(  x1 x2 ,…, xn ),xi∈{0,1},1≤i≤n,使得                  达到最大



输入

 第一行有2个正整数n和c。n是物品数,c是背包的容量。接下来的1 行中有n个正整数,表示物品的价值。第3 行中有n个正整数,表示物品的重量。

输出

 计算出装入背包物品的最大价值和最优装入方案。

样例输入

5 10
6 3 5 4 6
2 2 6 5 4

样例输出

15
1 1 0 0 1


先贴上递归形式实现的AC算法:

#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=10000;
int w[maxn];//w表示载重 
int p[maxn];//p表示收益 
int add[maxn];//表示是否加入 0为未加  1为加入 
int  KnapSack(int j,int x)  //算法返回最优解 
{
	if(j<0) return ((x<0)?-maxn:0);     //这一步防止递归超时  截止条件 
	if(x<w[j])
		return KnapSack(j-1,x);         //如果j的载重量大于剩下的载重量  则放弃这一个转入下一件物品的判断 
	else
	{
		int a=KnapSack(j-1,x);          //a表示  不放入第j 件物品 的情况的最优解 
		add[j]=1;                       //b表示   放入该物品的情况下的最优解 
		int b=KnapSack(j-1,x-w[j])+p[j];
		if(a>b)                     //比较 
		{
		    add[j]=0;                //若不放入第j物品的情况 获得的收益较大  则需要将j的add值置为0  
			return a;                 
		}
		else
			return b;
	}
}
int main()
{
	int n,c;
	while(scanf("%d %d",&n,&c)==2)
	{
		memset(add,0,sizeof(add));
		for(int i=0; i<n; i++)
			scanf("%d",&p[i]);
		for(int i=0; i<n; i++)
			scanf("%d",&w[i]);
		int res=0;
		res=KnapSack(n-1,c);//从第n-1物品开始向前计算 
		printf("%d\n",res);
		for(int i=0;i<n-1;i++)
		printf("%d ",add[i]);
		printf("%d\n",add[n-1]);
	}

}
    上述方法是以递归形式实现,耗时大,可换成一维数组实现,给出模板题POJ3624的AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn= 3500;
int w[maxn],p[maxn],dp[12880];
int main()
{
	int n,c;
	while(~scanf("%d%d",&n,&c))
	{
		memset(dp,0,sizeof(dp));
		for(int i=0; i<n; i++)
			scanf("%d%d",&w[i],&p[i]);
		for(int i=0; i<n; i++)
			for(int j=c; j>=w[i]; j--)
				dp[j]=max(dp[j],dp[j-w[i]]+p[i]);
		printf("%d\n",dp[c]);
	}
}
    具体理解可参见背包九讲。    

    特记下,以备后日回顾。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值