通天塔:奶牛们想用c_i个高h_i的积木造通天塔,每种积木不能高过a_i,求塔的最大高度。
多重背包 O(VN) 单调队列
这题要思考的方向是往多重背包这边想,高度既是“价值”又是“重量”,背包的容积是变动的a_i。性价比恒为1,优先使用a_i小的。必须按积木的a_i从小到大的顺序递推才能覆盖全部解空间,否则a_i小的积木根本码不上去。
多重背包的O(VN)优化是利用单调队列实现,我从这里现学现卖。
《2.3 记录结果再利用的“动态规划” 需稍加思考的题目》
#ifndef ONLINE_JUDGE #pragma warning(disable : 4996) #endif #include <iostream> #include <algorithm> #include <iterator> using namespace std; int f[2][40000 + 16]; pair <int, int> q[40000 + 16]; // 单调队列 first := 最优解 second:= 容积 struct Block { int h, a, c; bool operator < (const Block & b) const { return a < b.a; } }; Block block[400 + 16]; ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int K; cin >> K; for (int i = 0; i < K; ++i) { cin >> block[i].h >> block[i].a >> block[i].c; } sort(block, block + K); int cur = 0, pre = 1; for (int i = 0; i < K; ++i) { swap(cur, pre); int v, w, m; v = block[i].h; w = block[i].h; m = block[i].c; int V = block[i].a; // 价值 重量 数量 for (int mod = 0; mod < w; ++mod) { int l = 0, r = 0; // 单调队列 首 尾 for (int j = 0; mod + j * w <= V; ++j) { // 维持单调队列的递减特性 while (r > l && (f[pre][mod + j * w] - j * v) > q[r - 1].first) { // 将前面小的元素都挤出去 r--; } // 入队 q[r++] = make_pair(f[pre][mod + j * w] - j * v, j); if (r - l > 0 && j - q[l].second > m) { // 队列不为空,最优解对应的缺口无法填满,出队 l++; } f[cur][mod + j * w] = q[l].first + j * v; } } } cout << *max_element(f[cur], f[cur] + block[K - 1].a + 1) << endl; #ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout); system("out.txt"); #endif return 0; } ///////////////////////////End Sub//////////////////////////////////
12519522 | hankcs | 2392 | Accepted | 852K | 235MS | C++ | 1660B | 2014-02-14 01:17:02 |
马上要开始工作了,接着就开学,可能会减慢看《挑战程序设计竞赛(第2版)》的速度了。
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 2392 Space Elevator 题解 《挑战程序设计竞赛(第2版)》