断断续续动态规划学了五天了都要,今天一定要吧背包问题解决完去学STL
1、01背包问题:
有n件物品,每件物品的重量为W[i],价值为c[i].
现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大
其中每种物品都只有1件
【分析】
令dp[i][v]表示前i件物品恰好装入容量为v的背包中所能获得的最大价值
考虑对第i件物品的选择策略,有两种策略:
①不放第i件物品,问题转化为前i-1件物品恰好装入容量为v的背包中所能获得的最大价值
②放第i件物品,那么问题转化为前i-1件物品恰好装入容量为v-w[i]的背包中所能获得的最大价值
即dp[i-1][v-w[i]]+c[i]
因此
dp[i][v]=max{dp[i-1][v],dp[i-1][v-w[i]]+c[i]}
状态转移方程
注意到dp[i][v]只与之前的状态dp[i-1]有关
所以可以枚举i从1到n
v从0到V
通过边界dp[0][v]=0(即前0件物品放入任何容量v的背包中都只能获得价值0)
就可以把整个dp数组递推出来
而由于dp[i][v]表示的恰好是为v的情况
所以需要枚举dp[n][v],取最大值即为结果
for(int i=1;i<=n;i++)
{
for(int v=w[i];v<=V;v++)
{
dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]);
}
}
把空间复杂度减小
二维数组变为一维数组
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
for(int i=1;i<=n;i++)
{
for(int v=V;v>=w[i];v--)
{
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
}
}
注意逆序
二维数组顺序逆序皆可
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100
#define maxv 1000
int w[maxn],c[maxn],dp[maxv];
int main()
{
int n,V;
scanf("%d%d",&n,&V);
for(int i=0;i<n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&c[i]);
}
for(int v=0;v<=V;v++)
{
dp[v]=0;
}
int maxx=0;
for(int i=1;i<=n;i++)
{
for(int v=V;v>=w[i];v--)
{
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
}
}
for(int v=0;v<=V;v++)
{
if(dp[v]>maxx)
{
maxx=dp[v];
}
}
printf("%d\n",maxx);
return 0;
}
2、完全背包问题
【问题】
与01背包的区别就是 其中每件物品都有无穷件
dp[i][v]=max(dp[i-1][v],dp[i][v-w[i]]+c[i])
边界:dp[0][v]=0
转成一维
dp[v]=max(dp[v],dp[v-w[i]]+c[i])
正向顺序
for(int i=1;i<=n;i++)
{
for(int v=w[i];v<=V;v++)
{
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
}
}
01背包就是给定一个容量
然后每件物品只有一件
要怎么装才能使得价值最大
【01背包例题】
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
#define maxn 1010
int w[maxn],v[maxn],dp[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,V;
scanf("%d%d",&n,&V);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&v[i]);
}
for(int i=0;i<n;i++)
{
for(int j=V;j>=v[i];j--)
{
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
}
int max=0;
for(int i=1;i<=V;i++)
{
if(dp[i]>max)
{
max=dp[i];
}
}
printf("%d\n",max);
}
return 0;
}
【多重背包例题】
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
#define maxn 500010
int value[maxn],weight[maxn],dp[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int w1,w2;
scanf("%d%d",&w1,&w2);
int w=w2-w1;
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&value[i],&weight[i]);
}
for(int i=1;i<=w;i++)
{
dp[i]=maxn;
}
//dp[0]=0;
for(int i=0;i<n;i++)
{
for(int j=weight[i];j<=w;j++)
{
dp[j]=min(dp[j],dp[j-weight[i]]+value[i]);
}
}
if(dp[w]==maxn)
printf("This is impossible.\n");
else
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[w]);
}
return 0;
}