1 条题解

  • 0
    @ 2025-4-6 15:06:20

    题意:

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

    解题思路

    这个问题类似于经典的“背包问题”,但有一些额外的限制。我们需要选择一定数量的每种块,使得在堆叠时,每个块的顶部高度(即该块及其下方所有块的高度之和)不超过该块的aia_i。目标是最大化总高度HH

    1、关键点: 块的顺序:块的堆叠顺序会影响是否满足aia_i的限制。直观上,应该先放aia_i较小的块,因为这样它们可以放在较低的位置,避免超过其aia_i限制。

    例如,如果一个块的aia_i很小,那么它应该尽可能放在底部,这样它的顶部高度不会超过aia_i

    因此,首先需要将所有块按照aia_i从小到大排序。

    2、动态规划:类似于无限背包问题,但每种块的数量是有限的(多重背包问题)。

    定义dp[j]dp[j]为是否可以构建高度为j的塔,并且在构建时满足所有块的限制。

    初始化:dp[0]=Truedp[0] = True(高度为00总是可以构建)。

    对于每种块ii,按照排序后的顺序,考虑使用00cic_i个该块,更新dpdp数组。

    在更新时,需要确保新增的块不会违反其aia_i限制。即,如果当前已经堆叠了高度为jj的塔,新增一个块ii后,新的高度为j+hij + h_i,必须满足 j+hiaij + h_i ≤ a_i

    #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;
    }
    • 1

    信息

    ID
    1393
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者