您的位置:首页 > 其它

POJ 2392 Space Elevator 多重背包

2017-03-26 21:12 411 查看
构造最优解实际上取决于两个参数:1.当前海拔 2.能用的石块的集合

同时很容易想到要按照石块的最大海拔降序排列(升序也可以)

然后定义状态

为前i个砖块,在当前海拔为j的情况下能够堆叠的最大高度

然后便得到状态转移方程如下



和多重背包化简的方式类似,有两种情况

1.如果 h[i] * c[i] >= a[i] 说明在算第i个砖块的情况时, 不管当前海拔是多少,砖块的数量都足以使得海拔超过最大海拔。这也就相当于砖块的数量是“无限”的!这时候是完全背包

2.如果 h[i] * c[i] < a[i] 说明在当前海拔为某些数值的时候,砖块的数量不足以使得海拔超过最大值,换句话说也就是砖块的数量是“有限”的。这时候就要把砖块的数量按照1, 2, 4......这样2的次幂的形式拆分,然后使用0-1背包求解(原理请百度多重背包讲解)

多重背包情况下,状态转移方程可化简成:





0-1背包情况下,状态转移方程可化简成:



接下来套用多重背包模板就行了,同时可以将上述方程写成滚动数组的形式。

代码如下:

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX_N 500
#define MAX_H 40005
#define INF 0x3f3f3f3f

using namespace std;

typedef long long int ll;

struct Block
{
int h, a, c;
bool operator < (const Block b) const
{
return a > b.a;
}
};
Block blocks[MAX_N];
int dp[MAX_H];

int main()
{
//freopen("1.txt", "r", stdin);
//freopen("2.txt", "w", stdout);

int K;
cin >> K;
for (int i = 1; i <= K; i++)
scanf("%d%d%d", &blocks[i].h, &blocks[i].a, &blocks[i].c);
sort(blocks + 1, blocks + K + 1);

memset(dp, 0, sizeof(dp));
for (int i = 1; i <= K; i++)///多重背包
{
if (blocks[i].h * blocks[i].c >= blocks[i].a)///完全背包
{
for (int j = blocks[i].a - blocks[i].h; j >= 0; j--)
dp[j] = max(dp[j + blocks[i].h] + blocks[i].h, dp[j]);
}
else
{
int k = 1;
while (k < blocks[i].c)///0-1背包
{
for (int j = 0; j + k * blocks[i].h <= blocks[i].a; j++)
dp[j] = max(dp[j], dp[j + k * blocks[i].h] + k * blocks[i].h);
blocks[i].c -= k;
k <<= 1;
}
for (int j = 0; j + blocks[i].c * blocks[i].h <= blocks[i].a; j++)
dp[j] = max(dp[j], dp[j + blocks[i].c * blocks[i].h] + blocks[i].c * blocks[i].h);
}
}
printf("%d\n", dp[0]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 2392 多重背包 csdn