该题是纯粹的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>上述方法是以递归形式实现,耗时大,可换成一维数组实现,给出模板题POJ3624的AC代码:
#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]);
}
}
#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]);
}
}
特记下,以备后日回顾。