啊哈,经典的背包问题讲完了,这次呢,我们来总结一下背包问题,并整理程序。
总结
背包问题思路,就是将每一种放进去的情况都列举出来,并比较得到最优值,所以,就能求出最大值。这就是为什么背包问题中动态规划比普通递归要快,就是因为普通递归重复求了很多数值,而动态规划正好相反,把所有值存起来,对比值,求出,一般递归的时间复杂度是指数级,而动态规划基本上是平方级。
整理程序
(1) 01普通背包问题
#include<iostream>
#include<cstdio>
using namespace std;
int thing[1000001][3]; //重量(w)是thing[?][0],价值(c)是thing[?][1],f是thing[?][3]
int max(int a,int b)
{
return a>b? a:b;
}
int main()
{
int n,V;
cin>>V>>n;
for(int i=1;i<=n;i++) cin>>thing[i][0]>>thing[i][1];
for(int i=1;i<=n;i++)
for(int v=V;v>=thing[i][0];v--)
{
thing[v][2]=max(thing[v][2],thing[v-thing[i][0]][2]+thing[i][1]);
}
cout<<thing[V][2];
return 0;
}
(2)完全背包问题
#include<iostream>
#include<cstdio>
using namespace std;
int thing[1000001][3]; //如有数据内容不懂,请看上篇文章
int max(int a,int b)
{
return a>b? a:b;
}
int main()
{
int n,V;
cin>>V>>n;
for(int i=1;i<=n;i++) cin>>thing[i][0]>>thing[i][1];
for(int i=1;i<=n;i++)
for(int v=thing[i][0];v<=V;v++)
{
thing[v][2]=max(thing[v][2],thing[v-thing[i][0]][2]+thing[i][1]);
}
cout<<thing[V][2];
return 0;
}
(3)多重背包问题
#include<cstdio>
int v[10001],w[10001];
int f[6001];
int n,m,n1;
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x,y,s,t=1;
scanf("%d%d%d",&x,&y,&s);
while (s>=t)
{
v[++n1]=x*t;
w[n1]=y*t;
s-=t;
t*=2;
}
v[++n1]=x*s;
w[n1]=y*s; //把s以2的指数分堆:1,2,4,...,2^(k-1),s-2^k+1;
}
for(int i=1;i<=n1;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d",f[m]);
return 0;
(4)混合背包
#include<iostream>
using namespace std;
int f[1000001],n[1000001],w[1000001],c[1000001];
int main()
{
int N,V;
cin>>V>>N;
for(int i=1;i<=N;i++)
cin>>w[i]>>c[i]>>n[i];
for(int i=1;i<=N;i++)
{
if(n[i]!=0)
for(int j=1;j<=n[i];j++) //最多多少个
for(int v=V;v>=w[i];v--)
f[v]=max(f[v],f[v-w[i]]+c[i]);
else
for(int v=w[i];v<=V;v++)
f[v]=max(f[v],f[v-w[i]]+c[i]);
}
int max=-99999999;
for(int i=1;i<=V;i++) max=max<f[i]? f[i]:max;
cout<<max;
return 0;
}
(5)二维费用的背包问题
#include<cstdio>
#include<cstring>
using namespace std;
int v, u, k;
int a[1001], b[1001], c[1001];
int f[101][101];
int main()
{
memset(f,127,sizeof(f));
f[0][0] = 0;
scanf("%d%d%d",&v,&u,&k);
for (int i = 1; i <= k; i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
for (int i = 1; i <= k; i++)
for (int j = v; j >= 0; j--)
for (int l = u; l >= 0; l--)
{
int t1 = j+ a[i],t2 = l + b[i];
if (t1 > v) t1 = v; //若氮、氧含量超过需求,可直接用需求量代换,
if (t2> u) t2 = u;
if (f[t1][t2] > f[j][l] + c[i]) f[t1][t2] = f[j][l] + c[i];
}
printf("%d",f[v][u]);
return 0;
}
(6)分组背包
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int f[5000],c[5000],w[5000],a[5000][5000],i,j,n,m,s,k,t,p;
int main ()
{
cin>>n>>m>>t;
for (i=1; i<=m; i++)
{
cin>>w[i];
cin>>c[i];
cin>>p;
a[p][0]++;
a[p][a[p][0]]=i;
}
for (k=1; k<=t; k++)
for (i=n; i>=0; i--)
for (j=1; j<=a[k][0]; j++)
if (i>=w[a[k][j]])
f[i]=max(f[i],f[i-w[a[k][j]]]+c[a[k][j]]);
cout<<f[n];
return 0;
}
好了,背包问题到此结束,也希望大家多多学习掌握!