题目链接:http://poj.org/problem?id=3624
题目大意:01背包问题
N个物品,每个物品有两个属性,v(价值),w(重量),且每个物品只有一个。现有背包容量为M,求背包可承受范围内的最大价值。
题解:
DP(Dynamic Programming)即动态规划。每一步的选择会影响之后的状态。
我们设
状态3:dp[j] ->前i个物品在剩余容量为j的情况下的最大价值。
状态2:dp[j] ->没有选择物品i(前i-1个物品在容量为j的情况下的最大价值)
状态1:dp[j-item[i].w]+item.v ->选择了物品i(最大价值加上物品i的价值,容量减去物品i的重量)
状态3是状态1、2中的较大者。
个人见解:
1、首先我们需要对item按照w从小到大排序,我们要从重量小的物品开始选择。
为什么呢?如果我们从大的开始选择物品往背包里放,或者不排序就开始选择物品往背包里放。以前者为例:我们首先选择最大的重量的物品,但是装不满背包我们就需要再选择j-item[i].w容量内的物品,这时候dp[j-item[i].w]是0,因为我们初始化是0,并且我们先选择的是重量大的物品,也就有可能造成答案错误。
嗯,这里是错的,请看下面。
2、
for(int i=1;i<=N;i++)
for(int j=M;j>=item[i].w;j--)
{
dp[j]=max(dp[j],dp[j-item[i].w]+item[i].v);
}
这里的循环:
对第i个物品选择放与不放来保证dp是各个容量下当前的最大价值。就是像这样不断更新dp,最终得到答案。
3、内层循环从最大容量开始跑是为了避免重复选择物品。
(如果是这样:for(int j=item[i].w;j<=;j++),那么dp[item[i].w]状态选择了i物品是最大价值,那么dp[item[i].w*2]状态仍可能是选择i物品是最大价值,这种情况就是完全背包(物品的数量无限))
4、多重背包:物品的数量有限且数量不定。
这个时候就只需要将每个物品的数量用num数组存起来,然后再加一层循环:
也就是将2A看成A和A的叠加
for(int i=1;i<=N;i++)
for(int k=1;k<=num[i];k++)
for(int j=M;j>=k*item[i].w;j--)
{
dp[j]=max(dp[j],dp[j-item[i].w]+item[i].v);
}
1 * item[i].w
2 * item[i].w//上边跑完之后,(item[i].w+1)->2 * item[i].w是不会再次放物品i的
3 * item[i].w//与上边类似
……
k * item[i].w//与上边类似
所以直接将这中间不会放物品i的过程省略优化掉,就加了一个k * item[i].w,不加就会多跑一些时间。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxc=12888;//max_capacity->最大容量
const int maxN=3500;
int dp[maxc];
struct node
{
int v,w;
node(int a=0,int b=0):v(a),w(b){}
friend bool operator < (node n1,node n2)
{
return n1.w<n2.w;
}
}item[maxN];
int N,M,ans;
void init()
{
memset(dp,0, sizeof(dp));
ans=0;
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
init();
for(int i=1;i<=N;i++)
{
scanf("%d%d",&item[i].w,&item[i].v);
}
for(int i=1;i<=N;i++)
{
for(int j=M;j>=item[i].w;j--)
{
dp[j]=max(dp[j],dp[j-item[i].w]+item[i].v);
}
}
for(int i=M;i>=1;i--)
ans=max(ans,dp[i]);
printf("%d\n",ans);
}
return 0;
}