背包问题
一、01背包
现在有一个背包(容器),它的体积(容量)为V,现在有N种物品(每个物品只有一个),每个物品的价值v[i]和占用空间w[i]都会由输入给出,现在问这个背包最多能携带总价值多少的物品?
输入 4 5
3 2 4 2 2 1 3 2
输出 7
解析:此题可以用dp来做。因为每个物品都有取与不取两种情况,所以如果只看N的化会出现复杂度为2的n次方的爆炸情况,所以此地方需要考虑N和V
状态:a[i][j]表示到第i个物体为止,需要占用的最大空间为j。//注意这个地方是最大,所以循环中有一个比较问题,因为如果没占满空间的价值也有可能比原来高
转移:if(v>=w[i]) a[i][j]=max(a[i-1][j-w[i])+v[i],a[i-1][j]);//占满与没占满的比较
代码://空间复杂度为N*M,时间复杂度为N*M
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 110
using namespace std;
int N,W,v[maxn],w[maxn],s[maxn][10100];
int main()
{
while(cin>>N>>W&&W)
{
for(int i=1;i<=N;i++)
cin>>v[i];
for(int i=1;i<=N;i++)
cin>>w[i];
memset(s,0,sizeof(s));
for(int i=1;i<=N;i++)
{
for(int j=W;j>=0;j--)
{
if(j>=w[i])
s[i][j]=max(s[i-1][j-w[i]]+v[i],s[i-1][j]);
else
s[i][j]=s[i-1][j];
}
}
cout<<s[N][W]<<endl;
}
return 0;
}
改进:空间复杂度为W,二维坐标来回倒腾//如果设个k的话,注意++的位置在第一层循环,而不是第二层循环
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 110
using namespace std;
int N,W,v[maxn],w[maxn],s[2][10100];
int main()
{
while(cin>>N>>W&&W)
{
for(int i=1;i<=N;i++)
cin>>v[i];
for(int i=1;i<=N;i++)
cin>>w[i];
memset(s,0,sizeof(s));
int k=0;
for(int i=1;i<=N;i++)
{
for(int j=W;j>=0;j--)
{
if(j>=w[i])
s[i%2][j]=max(s[(i-1)%2][j-w[i]]+v[i],s[(i-1)%2][j]);//装还是不装
else
s[i%2][j]=s[(i-1)%2][j];
}
}
cout<<s[k%2][W]<<endl;
}
return 0;
}
改进:空间复杂度为W只用一维数组
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 110
using namespace std;
int N,W,v[maxn],w[maxn],s[10100];
int main()
{
while(cin>>N>>W&&W)
{
for(int i=1;i<=N;i++)
cin>>v[i];
for(int i=1;i<=N;i++)
cin>>w[i];
memset(s,0,sizeof(s));
for(int i=1;i<=N;i++)
{
for(int j=W;j>=0;j--)
{
if(j>=w[i])
s[j]=max(s[j-w[i]]+v[i],s[j]);
}
}
cout<<s[W]<<endl;
}
return 0;
}
二、完全背包
完全背包:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
//input
//3 7
//4 5 3
//3 4 2
//output
//10
//01背包:递推关系:s[i][j]=max(s[i+1][j],s[i+1][j-w[i]]+v[i]//是否选择这个物品,都会i加1
//完全背包递推关系:s[i+1][j]=max(s[i+1][j],s[i+1][j-k*w[i]]+v[i]);
// s[i+1][j-k*w[i]]+v[i](k>=0)=max(s[i+1][j-k*w[i]]+v[i]*k,s[i][j]);(k>=1)
// s[i+1][j-k*w[i]]+v[i]*k(k>=1)=s[i+1][j-w[i]]+v[i]
//综上: s[i+1][j]=max(max(s[i][j],s[i+1][j-w[i]]+v[i]),s[i+1][j])
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 110
using namespace std;
int N,W,v[maxn],w[maxn],s[maxn][10100];
int main()
{
while(cin>>N>>W&&W)
{
for(int i=1;i<=N;i++)
cin>>v[i];
for(int i=1;i<=N;i++)
cin>>w[i];
memset(s,0,sizeof(s));
for(int i=1;i<=N;i++)
{
for(int j=0;j<=W;j++)
{
if(j>=w[i])
s[i+1][j]=max(max(s[i+1][j-w[i]]+v[i],s[i][j]),s[i+1][j]);
else
s[i+1][j]=s[i][j];
}
}
cout<<s[N+1][W]<<endl;
}
return 0;
}
浙公网安备 33010602011771号