潜水员问题(二维背包)——挣扎后的结晶

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

题目我就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]是合法状态,即没有装氧气、氮气,气缸的重量为零,且其他设为无穷大,可以从使在当前背包容量下刚好满足或超出氧、氮气需求的背包组合中选择最小的气缸重量。

 

(这篇总结也是好几天前就的出来的,总之,写博客还是的当日事当日毕吧,整个背包问题的总结都拖好久了。。。

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页