啊哈,經典的揹包問題講完了,這次呢,我們來總結一下揹包問題,並整理程序。
總結
揹包問題思路,就是將每一種放進去的情況都列舉出來,並比較得到最優值,所以,就能求出最大值。這就是爲什麼揹包問題中動態規劃比普通遞歸要快,就是因爲普通遞歸重複求了很多數值,而動態規劃正好相反,把所有值存起來,對比值,求出,一般遞歸的時間複雜度是指數級,而動態規劃基本上是平方級。
整理程序
(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;
}
好了,揹包問題到此結束,也希望大家多多學習掌握!