01背包问题:
有n件物品,每件物品的重量为w[j],价值为c[j]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。其中每种物品都只有一件。
先采用暴力枚举解决此问题
解题思路:
①每一件物品放或者不放进背包(两种选择)
②若选择此物品,背包的容量V,和总价值W都要随之变化,返回选与不选的物品中价值最大值,否则,V,W都不需要变化
③注意临界条件:选择的物品总体积不可以超过总的体积,注意i的值
Code:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
int v,w;//物体的体积 物体的价值
};
vector<T>arr;
int f(int i,int j){//i:个数 j:体积 对第i个物体记性决策 当前已使用的体积为j
if(i==N)//边界条件 个数到达了规定的个数
return 0;
if(arr[i].v+j>M)//背包内已有的体积 +当前物体的体积>规定的背包体积
return f(i+1,j);//不选这个 继续往后走
//背包内已有的体积 +当前物体的体积≤规定的背包体积
return max(f(i+1,j),f(i+1,j+arr[i].v)+arr[i].w);//不选当前物体 个数加一 体积不变 价值也不变
//选当前物体 个数加一 体积加上当前物体体积 价值加上当前物体价值
}
int main(){
cin>>N>>M;//物品的个数 背包的体积
arr.resize(N);
for(int i=0;i<N;i++){
int a,b;
cin>>a>>b;
arr[i].v=a;
arr[i].w=b;
}
cout<<f(0,0);
return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5
****显然每件物品都有两种选择,因此n件物品就有
2
n
2^{n}
2n种情况,显然O(
2
n
2^{n}
2n)的复杂度是很糟糕的,而使用动态规划方法可以将复杂度降为O(nV)。
动态规划解决此问题:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
int v,w;//物体的体积 物体的价值
};
vector<T>arr;
vector<vector<int>>dp;
void fdp(){
for(int i=N-1;i>=0;i--){//从后往前推导
for(int j=0;j<=M;j++){
if(j+arr[i].v>M)//超出规定的体积
dp[i][j]=dp[i+1][j];//根据暴力枚举中这个 if(arr[i].v+j>M) return f(i+1,j); 式子得来
else
dp[i][j]=max(dp[i+1][j],dp[i+1][j+arr[i].v]+arr[i].w);
//根据暴力枚举中 max(f(i+1,j),f(i+1,j+arr[i].v)+arr[i].w); 这个式子得来
}
}
cout<<dp[0][0];
}
int main(){
cin>>N>>M;//物品的个数 背包的体积
arr.resize(N+1);//注意需要赋值为N+1 在第19行 i初始值为N-1 加一之后下标为N
dp.resize(N+1);
for(int i=0;i<=N;i++)
dp[i].resize(M+1);
for(int i=0;i<=N;i++)//为了保证最后一行是0
for(int j=0;j<=M;j++)
dp[i][j]=0;
for(int i=0;i<N;i++){
int a,b;
cin>>a>>b;
arr[i].v=a;
arr[i].w=b;
}
fdp();
return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5
进一步节省空间:一维数组
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
int v,w;//物体的体积 物体的价值
};
vector<T>arr;
vector<int>dp;
void fdp(){
for(int i=0;i<N;i++)//从左往右推导
for(int j=0;j<=M-arr[i].v;j++)//控制背包内的物品体积不能超过背包的最大可容纳的体积
dp[j]=max(dp[j],dp[j+arr[i].v]+arr[i].w);
cout<<dp[0];
}
int main(){
cin>>N>>M;//物品的个数 背包的体积
arr.resize(N);
dp.resize(N+1);
for(int i=0;i<N;i++)
dp[i]=0;
for(int i=0;i<N;i++){
int a,b;
cin>>a>>b;
arr[i].v=a;
arr[i].w=b;
}
fdp();
return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5