我們先來看分組背包問題
有N件物品和一個容量為V的背包,第i件物品的重量為c[i],價值為w[i],這些物品被划分成了若干組,每組中的物品互相沖突,最多選一件
問將哪些物品放入背包中可以使背包獲得最大的價值
我們用f[k][v]表示前k種物品花費費用v所能取得的最大價值
給出狀態轉移方程:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i屬於第k組}
可以看出,這個問題還是很顯然的,下面給出完整的實現:
在實現的時候稍微皮了一下~~
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int maxn=105; 6 const int maxv=105; 7 const int maxt=15; 8 int N,V,T; 9 int v[maxn],w[maxn]; 10 int f[maxv]; 11 int a[maxt][maxn]; 12 int main() 13 { 14 cin>>V>>N>>T; 15 for(int i=1;i<=N;i++) 16 { 17 int p; 18 cin>>v[i]>>w[i]>>p; 19 a[p][++a[p][0]]=i; //存每一組的所有物品的編號 20 //a[p][0]表示第p組一共有幾個物品 21 } 22 for(int i=1;i<=T;i++) 23 for(int j=V;j>=0;j--) 24 for(int k=1;k<=a[i][0];k++) 25 if(j-v[a[i][k]]>=0) 26 f[j]=max(f[j],f[j-v[a[i][k]]]+w[a[i][k]]); 27 cout<<f[V]<<endl; 28 return 0; 29 } 30
下面介紹有依賴的背包,參考題目為NOIP金明的預算方案
在這種背包中引入了主件和附件的概念,只有放了主件之后才能放與之相關聯的附件
最開始我是用生成組合的形式來解決這個問題的
即以主件為基准,和每一種附件的情況進行捆綁,再放01背包
但是我們有更皮的解決方法
將每一個主件對應的附件集合先做一次01背包
下面給出一道例題來實現這個方法,本例題中的主件是沒有價值的,如果主件有價值可以在這個的基礎上進行簡單的修改
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int maxn=55; 6 const int maxv=100005; 7 int tmp[maxv]; 8 int f[maxn][maxv]; 9 int N,V; //主件的數量,背包的容量 10 int main() 11 { 12 while(cin>>N>>V) 13 { 14 memset(f,0,sizeof(f)); 15 for(int i=1;i<=N;i++) 16 { 17 memset(tmp,-1,sizeof(tmp)); 18 int p,m; //主件的費用,附件的數量 19 cin>>p>>m; 20 for(int j=p;j<=V;j++) 21 tmp[j]=f[i-1][j-p]; 22 int v,w; 23 for(int j=1;j<=m;j++) 24 { 25 cin>>v>>w; //每一個附件的重量和價值 26 for(int k=V;k>=v;k--) 27 if(tmp[k-v]!=-1) 28 tmp[k]=max(tmp[k],tmp[k-v]+w); 29 } 30 for(int j=V;j>=0;j--) 31 f[i][j]=max(tmp[j],f[i-1][j]); 32 } 33 cout<<f[N][V]<<endl; 34 } 35 return 0; 36 }
另外,如果附件是另一件物品的主件,就是樹形動態規划了,參考選課那道題目,將在以后進行介紹