二維背包問題
一 問題描述:
二維費用的背包問題是指:
對於每件物品,具有兩種不同的費用;
選擇這件物品必須同時付出這兩種代價;對於每種代價都有一個可付出的最大值(背包容量)。
問怎樣選擇物品可以得到最大的價值。設這兩種代價分別為代價1和代價2,
第i件物品所需的兩種代價分別為a[i]和b[i]。兩種代價可付出的最大值(兩種背包容量)分別為V和U。物品的價值為w[i]。
f[i][u][v] = max(f[i-1][u][v] , w[i] + f[i-1][u-a[i]][v-b[i]])
二 加深
同樣的解決二維費用背包的只需要增加一維數組即可,即建立f[u][v]數組
當為完全背包時候,uv正序,當為01背包的時候uv倒序。
當存在多重背包問題的時候,就需要將多重背包轉換為01背包的情況。
三 源代碼分析
#include <iostream> using namespace std ; const int V = 1000 ; //總成本b const int U = 1000 ; //總成本a const int T = 5 ; //物品的種類 int f[U+1][V+1] ; //可以不裝滿 int w[T] = {8 , 10 , 4 , 5 , 5}; //價值 int a[T] = {600 , 400 , 200 , 200 , 300}; //每一個的體積 int b[T] = {800 , 400 , 200 , 200 , 300}; const int INF = -66536 ; int package() { for(int i = 1 ; i <= U ;i++) //條件編譯,表示背包可以不存儲滿 for(int j = 1 ; j <= V ;j++) f[i][j] = INF ; f[0][0] = 0 ; //01 for(int i = 0 ; i < T ; i++) { for(int u = U ; u >= a[i] ;u--) //必須全部從V遞減到0 { for(int v = V ; v >= b[i] ;v--) f[u][v] = max(f[u-a[i]][v-b[i]] + w[i] , f[u][v]) ; //此f[v]實質上是表示的是i-1次之前的值。 } } return f[U][V] ; } int main() { int temp = package() ; cout<<temp<<endl ; system("pause") ; return 0 ; }
杭電2159 二維背包加完全背包:
FATE
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3943 Accepted Submission(s): 1741
Problem Description
最近xhd正在玩一款叫做FATE的游戲,為了得到極品裝備,xhd在不停的殺怪做任務。久而久之xhd開始對殺怪產生的厭惡感,但又不得不通過殺怪來升完這最后一級。現在的問題是,xhd升掉最后一級還需n的經驗值,xhd還留有m的忍耐度,每殺一個怪xhd會得到相應的經驗,並減掉相應的忍耐度。當忍耐度降到0或者0以下時,xhd就不會玩這游戲。xhd還說了他最多只殺s只怪。請問他能升掉這最后一級嗎?
Input
輸入數據有多組,對於每組數據第一行輸入n,m,k,s(0 < n,m,k,s < 100)四個正整數。分別表示還需的經驗值,保留的忍耐度,怪的種數和最多的殺怪數。接下來輸入k行數據。每行數據輸入兩個正整數a,b(0 < a,b < 20);分別表示殺掉一只這種怪xhd會得到的經驗值和會減掉的忍耐度。(每種怪都有無數個)
Output
輸出升完這級還能保留的最大忍耐度,如果無法升完這級輸出-1。
Sample Input
10 10 1 10 1 1 10 10 1 9 1 1 9 10 2 10 1 1 2 2
Sample Output
0 -1 1
本題是求經驗值的最大值,在最大值大於升級的最大值時,在判斷何時就已經可以升級了,此時求出所要付出的忍耐值!!
#include<stdio.h> #include<string.h>
int main() { int i,j,n,m,f[120][120],s,k,a[120],b[120],z; while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF) { memset(f,0,sizeof(f)); for(i=0;i<k;i++) scanf("%d%d",&a[i],&b[i]); for(i=0;i<k;i++) for(j=1;j<=s;j++)//注意動物的開始數是1 for(z=b[i];z<=m;z++) f[j][z]=f[j][z]>(f[j-1][z-b[i]]+a[i])?f[j][z]:(f[j-1][z-b[i]]+a[i]);//注意要j-1 if(f[s][m]>=n) { for(i=0;i<=m;++i) if(f[s][i]>=n) { printf("%d\n",m-i); break; } } else printf("-1\n"); } return 0; }