【C++揹包】超級揹包大集合

啊哈,經典的揹包問題講完了,這次呢,我們來總結一下揹包問題,並整理程序。

總結

揹包問題思路,就是將每一種放進去的情況都列舉出來,並比較得到最優值,所以,就能求出最大值。這就是爲什麼揹包問題中動態規劃比普通遞歸要快,就是因爲普通遞歸重複求了很多數值,而動態規劃正好相反,把所有值存起來,對比值,求出,一般遞歸的時間複雜度是指數級,而動態規劃基本上是平方級。

整理程序

(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; 
}

好了,揹包問題到此結束,也希望大家多多學習掌握!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章