背包问题

1 01背包问题

有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

解法:我们用dp[i][j]表示前i件物品重量不超过j的最大价值,则dp方程为

j>w[i]时,dp[i][j]=max{dp[i-1][j],dp[i-1][j-w[i]]+c[i]}

j<=w[i]时,dp[i][j]=dp[i-1][j].

其中dp[i-1][j]表示第i件物品无法放在背包里的价值,dp[i-1][j-w[i]]+c[i]表示第i件物品放入背包里的最大价值,我们选择其中的较大的。

优化:

采用一维数组来优化dp[v],我们必须保证dp[v]及dp[v-w[i]]是前一个状态的值,及前i-1件物品的最大价值,如何保证这个无后效性呢,采用逆序

dp[v]=max{dp[v],dp[v-w[i]]+c[i]},这样计算出来的每一个新的dp[v]都不会影响当前循环的后面的结果,核心代码:

for(i=1;i<=n;i++)

for(v=V;v>=w[i];v--)

dp[v]=max{dp[v],dp[v-w[i]]+c[i]};

2.完全背包

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

解法:

仍然采用刚才的思路,用dp[i][j]表示前i件物品重量不超过j的最大价值,则dp方程为:

dp[i][j]=max{dp[i-k*w[i]]+k*c[i]},0<=k*w[i]<=j

我们对这个也采用一维数组进行优化,令dp[v]表示dp[i][v],由于这个问题中物品是无穷件,所以我们不用考虑前一个状态,只考虑当前状态,即

for(i=1;i<=n;i++)

for(v=w[i];v<=V;v++)

dp[v]=max{dp[v],dp[v-w[i]]+c[i]};

这个和01背包的区别就是因为物品是无限的,我们可以累计的将第i件物品加入到当前状态中。

3.多重背包

有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

dp方程为:dp[i][j]=max{dp[i-1][j-k*w[i]+k*c[i]]},0<=k<=n[i]

对应这个题,由于物品件数有限,我们需要遍历一遍n[i],即将k个第i件物品放入当前背包,选择最大的那个。

for(i=1;i<=n;i++)

for(j=0;j<n[i];j++)//即循环n[i]次,选择最大的dp[v]

for(v=V;v>=w[i];v--)

dp[v]=max{dp[v],dp[v-w[i]]+c[i]};

poj1276 ,多重背包问题,但是由于数比较大超时了,必须经过优化,以后有时间再看吧,下面是我超时的代码:

#include <iostream>
#include <stdio.h>
using namespace std;
const int N=100001;
int dp[N+2],weight[N],num[N],total,n;
int main()
{
	int i,j,k;
	while(scanf("%d%d",&total,&n)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%d%d",&num[i],&weight[i]);
		for(i=0;i<=total;i++)
			dp[i]=0;
		if(!total || !n)
		{
			printf("%d\n",0);
			continue;
		}
		for(i=1;i<=n;i++)
		{
			for(j=0;j<num[i];j++)
			{
				for(k=total;k>=weight[i];k--)
				{
					if(dp[k]<(dp[k-weight[i]]+weight[i]))
						dp[k]=dp[k-weight[i]]+weight[i];
				}
			}
		}
		printf("%d\n",dp[total]);
	}
	return 0;
}


posted on 2011-10-15 21:39  buptLizer  阅读(322)  评论(0编辑  收藏  举报

导航