第一种,0-1背包
0-1背包大多解决的的问题时,给你一个容量为V的背包,给你n个物品以及每个物品的价值和重量,每个物品中有一个。
让你在不超出背包容量的情况下尽可以装价值更大的东西。(刚开始可以用二维dp数组来写,也可以优化为以为数组节约空间)。
eg:
5 10
6 3 5 4 6 0 0 6 6 6 6 6 6 6 6 6
2 2 6 5 4 0 0 6 6 9 9 9 9 9 9 9
0 0 6 6 6 6 6 6 11 11 14
0 0 6 6 9 9 9 10 11 13 14
0 0 6 6 9 9 12 12 15 15 15
二维dp解法:
#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
LL dp[1000][1000],n,m,v[1000],c[1000];
memset(dp,0,sizeof(0));
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i];
for(int i=1;i<=n;i++)
cin>>c[i];
for(int i=1;i<=n;i++)
{
for(int j=0;j<c[i];j++)
dp[i][j]=dp[i-1][j];
for(int j=c[i];j<=m;j++)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+v[i]);
}
for(int i=1;i<=n;i++)//输出背包大小不超过输入容量下的能装的最大价值
{
for(int j=0;j<=m;j++)
cout<<dp[i][j]<<" ";
cout<<endl;
}
}
优化一维数组
#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
LL dp[1000],n,m,v[1000],c[1000];
memset(dp,0,sizeof(0));
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i];
for(int i=1;i<=n;i++)
cin>>c[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=c[i];j--)
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
for(int j=0;j<=m;j++)
cout<<dp[j]<<" ";
cout<<endl;
}
}
第二种,完全背包:
完全被包与0-1背包的区别就是完全背包里的物品数量是无限个,完全背包与0-1背包代码实现相差不大
dp数组正着更新是完全背包,倒着更新是0-1背包;
#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
LL dp[1000],n,m,v[1000],c[1000];
memset(dp,0,sizeof(0));
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i];
for(int i=1;i<=n;i++)
cin>>c[i];
for(int i=1;i<=n;i++)
{
for(int j=c[i];j<=m;j--)
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
for(int j=0;j<=m;j++)
cout<<dp[j]<<" ";
cout<<endl;
}
}
第三种,多重背包:
多重背包就是背包里物品数量不为一但是有限,相当于介于0-1背包与完全背包之间,一般解决多重背包问题把
0-1背包与完全背包结合起来使用,而且一般0-1背包可以用二进制压缩来优化,降低时间复杂度
#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int v[1005];
int d[1005];
int dp[100005];
int n,m;
void zero(int v)
{
for(int i=m;i>=v;i--)
{
dp[i]=max(dp[i],dp[i-v]+v);
}
}
void complete(int v)
{
for(int i=v;i<=m;i++)
{
dp[i]=max(dp[i],dp[i-v]+v);
}
}
void f(int v,int d)
{
if(v*d>=m)
complete(v);//完全背包
else
{
int k=1;
while(k<=d)
{
zero(k*v);//0-1背包
d-=k;
k*=2;//二进制优化
}
zero(v*d);
}
}
int main()
{
while((cin>>n>>m)&&(n||m))
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++)
dp[i]=-INF;
for(int i=1;i<=n;i++)
cin>>v[i];
for(int i=1;i<=n;i++)
cin>>d[i];
for(int i=1;i<=n;i++)
f(v[i],d[i]);
int ans=0;
for(int i=1;i<=m;i++)
if(dp[i]>0)
ans++;
cout<<ans<<endl;
}
}