POJ 2392 Space Elevator(多重背包变形)

Q: 额外添加了最大高度限制, 需要根据 alt 对数据进行预处理么?

A: 是的, 需要根据 alt 对数组排序

 

Description

The cows are going to space! They plan to achieve orbit by building a sort of space elevator: a giant tower of blocks. They have K (1 <= K <= 400) different types of blocks with which to build the tower. Each block of type i has height h_i (1 <= h_i <= 100) and is available in quantity c_i (1 <= c_i <= 10). Due to possible damage caused by cosmic rays, no part of a block of type i can exceed a maximum altitude a_i (1 <= a_i <= 40000). 

Help the cows build the tallest space elevator possible by stacking blocks on top of each other according to the rules.

Input

* Line 1: A single integer, K 

* Lines 2..K+1: Each line contains three space-separated integers: h_i, a_i, and c_i. Line i+1 describes block type i.

Output

* Line 1: A single integer H, the maximum height of a tower that can be built

Sample Input

3
7 40 3
5 23 8
2 52 6

Sample Output

48

Hint

OUTPUT DETAILS: 

From the bottom: 3 blocks of type 2, below 3 of type 1, below 6 of type 3. Stacking 4 blocks of type 2 and 3 of type 1 is not legal, since the top of the last type 1 block would exceed height 40.
 

思路:

  1. 对数据预处理, 按照 alt 排序
  2. 预处理, 倍增优化, 转化成 01 背包
  3. 求解 01 背包

总结:

1. 对 3 个数组, 以其中一个为根据排序, 一种解决方法是把三个数组绑定到一个对象中, 然后对对象排序

2. 犯了个致命的错误, 48行代码写成memset(dp, 0, sizeof(int)*V); 导致当 V 比较大时, h 也被置 0 了

 

代码:

#include <iostream>
#include <algorithm>
using namespace std;
int K;
const int MAXN = 40010;
bool dp[40010];
int h[MAXN], a[MAXN];
int V;

struct block {
	int h, a, c;
	bool operator<(const block &other) const {
		return this->a < other.a;
	}
};

block blocks[MAXN];
int pre_process() {
	sort(blocks, blocks+K);
	int len = 0;
	for(int i = 0; i < K; i ++) {
		int rem = blocks[i].c;
		int j = 0;
		// 预处理, 
		while(rem) {
			if(rem >= (1<<j)) {
				h[len] = (1<<j)*blocks[i].h;
				a[len] = blocks[i].a;
				rem -= (1<<j);
				j++;
				if(h[len] > a[len])
					continue;
				len++;
			}else{
				h[len] = rem*blocks[i].h;
				a[len] = blocks[i].a;
				len++;
				rem = 0;
			}
		}
	}
	return len;
}

int solve_dp() {
	int len = pre_process();
	// 01背包
	memset(dp, 0, sizeof(dp));
	dp[0] = 1;
	for(int i = 0; i < len; i ++) {
		for(int v = V; v >= h[i]; v--) {
			if(v > a[i]) continue;
			if(!dp[v] && dp[v-h[i]]) {
				dp[v] = true;
				//printf("dp[%d] = true\n", v);
			}
		}
	}

	for(int v = V; v >= 0; v --)
		if(dp[v])
			return v;
}
int main() {
	freopen("E:\\Copy\\ACM\\测试用例\\in.txt", "r", stdin);
	cin >> K;
	int h_i, a_i, c_i;
	V = 0;
	for(int i = 0; i < K; i ++) {
		scanf("%d%d%d", &blocks[i].h, &blocks[i].a, &blocks[i].c);
		V = min(V+blocks[i].h*blocks[i].c, 40000);
	}

	cout << solve_dp() << endl;
	return 0;
}

  

update: 2014年3月14日10:35:10

1. 贪心策略是最大高度较小的先放

 

Q1: 对物品排序会对结果产生影响吗

A1: 会的. 假设只有两个物品, 最大高度不同, 显然最大高度较小的放前面可以获摆放的更高

 

Q2: 第二层循环, V 是怎么初始化的

A2: 上面的代码初始化比较随意, V 初始化为 40000 和 所有梯子高度之和 的较小值

posted @ 2013-12-08 15:20  SangS  阅读(427)  评论(0编辑  收藏  举报