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.
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.
* 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.
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.
思路:
- 对数据预处理, 按照 alt 排序
- 预处理, 倍增优化, 转化成 01 背包
- 求解 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 和 所有梯子高度之和 的较小值