首页 > 代码库 > POJ 2392 Space Elevator(贪心+多重背包)

POJ 2392 Space Elevator(贪心+多重背包)

POJ 2392 Space Elevator(贪心+多重背包)

http://poj.org/problem?id=2392

题意:

       题意:给定n种积木,每种积木都有一个高度h[i],一个数量num[i],还有一个限制条件,这个积木所在的位置不能高于limit[i],问能叠起的最大高度?

分析:

       本题是一道多重背包问题, 不过每个物品的选择不仅仅要受该种物品的数量num[i]限制, 且该物品还受到limit[i]的限制.

这里有一个贪心的结论:

       我们每次背包选取物品时都应该优先放置当前limit[i]值最小的积木(可以画个图看看,不过不太好证明该结论). 所以我们首先把所有积木按limit[i]的值进行从小到大的排序, 然后从1编号开始选积木即可.

       下面就是多重背包的过程了.

       令dp[i][j]==x表示用前i个积木且总的高度<=j时能达到的最大高度为x.

       初始化: dp全为0.

       对于每种物品, 我们要做两种选择:

       1.    num[i]*high[i]>=limit[i]时, 做一次完全背包.

       2.    Num[i]*high[i]<limit[i]时, 需要把当前物品再分类, 然后做多次01背包即可.

       最终所求: dp[n][j]的最大值. 其中j遍历[0,limit[n]]内所有数.

       注意: 本来按道理dp[i][j]的语义是<=j时, 而不是正好等于j时. 我们直接输出dp[n][limit[n]]即可的. 但是本题有点特殊. 看下面这组数据:

2

5 11 3

8 12 2

       对应的最终dp输出为:

i=0 dp[i]=0

i=1 dp[i]=0

i=2 dp[i]=0

i=3 dp[i]=0

i=4 dp[i]=0

i=5 dp[i]=5

i=6 dp[i]=5

i=7 dp[i]=5

i=8 dp[i]=8

i=9 dp[i]=8

i=10 dp[i]=10

i=11 dp[i]=10

i=12 dp[i]=8

       为什么会得到上面奇怪的数据呢? 因为当选择第1个物品(high[1]==5)时, 进行的背包过程只做到了11高度就停了, 没有继续到所有数据. 所以最终需要遍历所有dp数据.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=40000+5;

int n;//木块种类
struct Node//每种木块
{
    int high,num,limit;
    bool operator<(const Node &rhs)const
    {
        return limit<rhs.limit;
    }
}nodes[400+5];
int dp[maxn];

//一次01背包过程
void ZERO_ONE_PACK(int cost,int limit)
{
    for(int i=limit;i>=cost;i--)
        dp[i] = max(dp[i], dp[i-cost]+cost);
}

//一次完全背包过程
void COMPLETE_PACK(int cost,int limit)
{
    for(int i=cost;i<=limit;i++)
        dp[i] = max(dp[i], dp[i-cost]+cost);
}

//一次多重背包过程
void MULTIPLY_PACK(int cost,int limit,int num)
{
    if(cost*num>=limit)
    {
        COMPLETE_PACK(cost,limit);
        return ;
    }

    int k=1;
    while(k<num)
    {
        ZERO_ONE_PACK(cost*k,limit);
        num-=k;
        k*=2;
    }
    ZERO_ONE_PACK(cost*num,limit);
}

int main()
{
    while(scanf("%d",&n)==1)
    {
        //读取输入+排序
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&nodes[i].high,&nodes[i].limit,&nodes[i].num);
        sort(nodes+1,nodes+n+1);

        //初始化dp+递推
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            MULTIPLY_PACK(nodes[i].high, nodes[i].limit, nodes[i].num);

        //统计结果输出
        int ans=0;
        for(int i=0;i<=nodes[n].limit;i++)
            ans=max(ans,dp[i]);
        printf("%d\n",ans);
    }
    return 0;
}

POJ 2392 Space Elevator(贪心+多重背包)