1. 程式人生 > >二維揹包——傷腦筋的潛水員問題。

二維揹包——傷腦筋的潛水員問題。

好吧是我太菜,看著答案想了好久。

題目我就ctrl + v過來了啊+_+!

潛水員

Time Limit:10000MS  Memory Limit:65536K Total Submit:104 Accepted:56  Case Time Limit:1000MS

Description

潛水員為了潛水要使用特殊的裝備。他有一個帶2種氣體的氣缸:一個為氧氣,一個為氮氣。讓潛水員下潛的深度需要各種的數量的氧和氮。潛水員有一定數量的氣缸。每個氣缸都有重量和氣體容量。潛水員為了完成他的工作需要特定數量的氧和氮。他完成工作所需氣缸的總重的最低限度的是多少?  例如:潛水員有5個氣缸。每行三個數字為:氧,氮的(升)量和氣缸的重量:  3 36 120  10 25 129  5 50 250  1 45 130  4 20 119  如果潛水員需要5升的氧和60升的氮則總重最小為249 (1,2或者4,5號氣缸)。  你的任務就是計算潛水員為了完成他的工作需要的氣缸的重量的最低值。 

Input

從文字檔案gas.in中讀入資料。  第一行有2整數t,a(1<=t<=21,1<=a<=79)。它們表示氧,氮各自需要的量。  第二行為整數n (1<=n<=1000)表示氣缸的個數。  此後的n行,每行包括ti,ai,wi(1<=ti<=21,1<=ai<=79,1<=wi<=800)3整數。這些各自是:第i個氣缸裡的氧和氮的容量及汽缸重量。 

Output

僅一行包含一個整數,為潛水員完成工作所需的氣缸的重量總和的最低值。 

Sample Input

5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119

Sample Output

249

Source

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 1001;
int dp[maxn][maxn];
int a[maxn], b[maxn], w[maxn];
int main() {
	int u, v, k;//u->氧, v->氮
	memset(dp,127,sizeof(dp));//將127賦給dp的每個位元組,使陣列中每個數都很大。
	dp[0][0] = 0;//#1
	cin >> u >> v;
	cin >> k;
	
	for(int i = 1; i <= k; i++)
		cin >> a[i] >> b[i] >> w[i];
	
	for(int i = 1; i <= k; i++)
		for(int j = u; j >= 0; j--)
			for(int t = v; t >= 0; t--){
				t1 = a[i] + j;//#2
				t2 = b[i] + t;
				if(t1 > u)  t1 = u;
				if(t2 > v)	t2 = v;
				if(dp[t1][t2] > dp[j][t]+w[i])//#3
					dp[t1][t2] = dp[j][t]+w[i];
			}
	
	cout << dp[u][v];
} 

拿到這個題...題意好理解,就是選擇氣缸使氧氣和氮氣都充足的情況下,使氣缸加起來總重量最小。

想了想,在二維費用的基礎上這與之前的那些揹包題的問法感覺差距好大,“揹包”沒有重量限制了,而且求的是最小“價值”,真的有點不知所措。

掙扎了好久還是看了答案,發現答案都看不明白,有些式子也是,“莫名”地蹦出來...,而且答案備註,網上blog(好,這是題目,這是個二維揹包問題...然後source,over, 都說了跟沒說一樣,鬧心啊啊,還在回頭自己想why。

總之,期間可以說是掙扎了很久,現在就來分享下我當初的疑惑和思考吧。

無非就是抓著問題問自己該怎麼做,怎麼實現。(這說著容易,當時真的不知怎麼下手,所以還是講程式碼怎麼來的吧。

當時最想不通的是為什麼要借t1,t2這兩個變數,為什麼得等於j+a[i],t+b[i],這知道了的話後面的語句也就清楚了。

#2 其實這是由揹包問題的內層迴圈得來,揹包問題的內層迴圈和狀態轉換的意義在於,由“有意義”{這裡意思是實際物品的重量加進來可以超過揹包的最大容量,不過那就沒有意義了,但是這裡的氧氣(物品)的總和可以超出氣缸的需要量(揹包)}的最大容量開始到0(或w[i])都裝一遍,使在每個容量下從當前可選物品中選出最大價值。

#3 所以他應該從u+a[i]這個實際最大值開始遍歷,這樣轉換條件中t1 = j+a[i] (範圍由u+a[i] 到a[i])再減去a[i](物品重量)所得到的dp[j][i] +c[i]與dp[t1][t2]進行比較才有意義(這樣dp[t1-a[i]][t2-b[i]](dp[j][t])的重量選擇範圍是可以a[i]、b[i]到u、v。不然超過了u或者v,直接拿u-a[i]得到的dp值就不符合轉換本意)

其中當氧氣(物品重量)超過u時就使t1等於u 。為什麼呢?這同上面“有意義“相同,我們要求的是dp[u][v]所以此時當氧氣重量超過u或者v時,效果等價於等於u或者v的情況,因為他們都滿足需求。

#1 最後要滿足就氧、氮氣含量的同時使氣缸重量最小,就得將dp陣列除f[0][0]以外全賦值無窮大。因為只有f[0][0]是合法狀態,即沒有裝氧氣、氮氣,氣缸的重量為零,且其他設為無窮大,可以從使在當前揹包容量下剛好滿足或超出氧、氮氣需求的揹包組合中選擇最小的氣缸重量。

(這篇總結也是好幾天前就的出來的,總之,寫部落格還是的當日事當日畢吧,整個揹包問題的總結都拖好久了。。。