1. 0-1背包问题
0-1背包问题模型:
一个总容量V的背包和N件物品,每件物品都有其体积w,价值v;每个物品是否在背包中即0-1情况,故称该种问题为0-1背包问题。要求背包能装下价值尽可能多的物品,求最大价值;
状态描述:dp[i][j]表示第i件物品对于当前占用容量为j的价值状态,其中1<=i<=n,0<=j<=V;
状态分析:第i件物品是否加入背包,
(1)加入,dp[i][j]等于dp[i-1][j-w]+v,第i-1件相对于j-wi的占容最大价值的最大价值加第i件价值;
(2) 没加入,d[i][j]等于dp[i-1][j],即与第i-1件到j占容的最大价值;
状态转换:
转换结果:dp[N][V],第N件物品到占容为V的最大价值状态
测试数据:
70 3
71 100
69 1
1 2状态分析表如下所示:
i \ j 1 2 ... 68 69 70 1 0 0 ... 0 0 0 2 0 0 ... 0 0+1 0+1 3 2 0+2 ... 2 0+2 1+2
Code:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;//V为容量,N为个数
vector<int> dpcol(1000,0);
vector<vector<int>> dp(100,dpcol);//N<=100,V<=1000
struct goods{
int w;//权重或表示为占容
int v;//价值value
};
vector<goods> goods(100,{0,0});
int main(){
int w,v;
while(cin>>V>>N){
for(int i=1;i<=N;i++){
cin>>w>>v;
goods[i]={w,v};
}//输入物品
for(int j=1;j<=V;j++){//0件物品的所有价值为0
dp[0][j]=0;
}//初始化第0件状态
for(int i=1;i<=N;i++){//物品V
for(int j=V;j>=goods[i].w;j--){//倒序,由上一轮数据更新,能放入i物品
dp[i][j]=max(dp[i-1][j-goods[i].w]+goods[i].v,dp[i-1][j]);
}
for(int j=goods[i].w-1;j>=0;j--){//不能放入i物品,照抄上一轮到j的价值,且//保证了dp[i][0]=0;
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[N][V]<<endl;
}
return 0;
}
/**
70 3
71 100
69 1
1 2
3
*/
优化Code:
1.dp只受上一轮结果影响,故将二维dp[i][j]一维话dp[j]。
2.for(V....goods[i].w) dp[j],未加入i物品时暂存上一轮dp,省略了二维的抄作业行为。
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;
int w,v;
vector<int> dp(101,0);
struct goods{
int w,v;
};
vector<goods> goods(101,{0,0});
int main(){
while(cin>>V>>N){
for(int i=1;i<=N;i++){
cin>>w>>v;
goods[i]={w,v};
}
for(int j=0;j<V;j++){
dp[j]=0;
}
for(int i=1;i<=N;i++){
for(int j=V;j>=goods[i].w;j--){
dp[j]=max(dp[j],dp[j-goods[i].w]+goods[i].v);
}
}
cout<<dp[V]<<endl;
}
return 0;
}