关于背包问题:
众所皆知,这里讲给出关于背包问题的一些简介:
一个旅行者准备随身携带一个背包. 可以放入背包的物品有n 种, 每种物品的重量和价值分别为 wj , vj . 如果背包的最大重量限制是 b, 怎样选择放入背包的物品以使得背包的价值最大?
先思考一个问题:就是每种物品可以重复选择,这种要怎么解决:
Fk(y):装前 k 种物品, 总重不超过 y, 背包的最大价值;
这里的子问题:很好理解,想一想,每一次你要去拿物品,你会想,
如果,只拿一个物品并且包包还能装下的最大价值是多少;
如果,要拿两个物品并且包包能装下的最大价值是多少;
。。。
然而,如果不用动态规划: 每一次,多拿一个物品,就要从第一个物品(前提是包包能装下)去开始拿,,,,你不觉得,这是在做无用功吗?
其实说是这么说,真正的去理解递推公式,还是有一点难的:
v1=1, v2=3, v3=5,v4=9,
w1 =2, w2 =3, w3 =4, w4 =7,
b
= 10
Fk(y)
的计算表如下:(利用递推的公式:Fk
( y)
= max{Fk
−1
( y),
Fk
( y
− wk
) +
vk
} )
代码:
#include <iostream>
#include <cstring>
#define MM 12882
using namespace std;
#define NUM 100
int main11()//同一个物品物品可以多次选择;
{
int V[NUM],W[NUM];//表示每个物品的价值和大小;
int dp[2][MM];
int N,M;//物品数;和最大重量;
cin>>N>>M;
for(int i = 1;i<=N;i++){
cin>>W[i]>>V[i];
}
memset(dp,0, sizeof(dp));
for(int i = 1;i<=N;i++){
for(int j = 1;j<=M;j++){
if(j-W[i]>=0)
dp[i%2][j] = max(dp[(i-1)%2][j],dp[i%2][j-W[i]]+V[i]);
else{
dp[i%2][j] = dp[(i-1)%2][j];
}
}
// for(int j = 0;j<=M;j++)
// cout <<dp[i%2][j]<<" ";
// cout <<endl;
}
cout <<dp[N%2][M]<<endl;
return 0;
}
//4 10
//2 1
//3 3
//4 5
//7 9
然而:如果是物品不能重复选择的:
递推方程:Fk ( y) = max{Fk −1 ( y), Fk-1 ( y − wk ) + vk}
思路和上面的一模一样;poj3624
//4 6
//1 4
//2 6
//3 12
//2 7
#include <iostream>
#include <cstring>
#define NN 3204
#define MM 12882
using namespace std;
int main()//同物品不能重选;
{
int W[NN],V[NN];
int N,M;
cin >>N>>M;
for(int i = 1 ;i<=N;i++)
cin>>W[i]>>V[i];
//输如数据;
int dp[2][MM];
memset(dp, 0, sizeof(dp));
for(int i = 1;i<=N;i++){
for(int j = 1;j<=M;j++){
if(j-W[i]>=0)
dp[i%2][j] = max(dp[(i-1)%2][j],dp[(i-1)%2][j-W[i]]+V[i]);
else
dp[i%2][j] =dp[(i-1)%2][j];
}
}
cout << dp[N%2][M]<<endl;
return 0;
}