需要排序的01背包———>hdu 3466 &&贪心 hdu 3177

本文探讨了在特定条件下,使用动态规划(DP)解决背包问题的策略,特别是通过排序物品来优化解决方案的方法。文章介绍了两种不同的思路,一种是以kuangbin为代表的不更新范围递增策略,另一种是通过计算不同购买顺序所需最小金额来决定最优路径的策略。此外,还详细解释了如何在DP过程中应用0-1背包思想,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了很多博客,有以下两种思路:

以kuangbin神为代表:q-p其实就是不更新的范围,不更新的范围从小到大递增时就不会影响后面的DP了。

以很多很多人为代表:对任意两个物品i,j,为了避免上面存在的那种问题,我们可以算出两种顺序所需要的最少金额,若i->j,则至少需要Pi+Qj,若是j->i则至少需要Pj+Qi。如果已知结果是i->j较优的话,则有Pi+Qj<Pj+Qi,即Qi-Pi>Qj-Pj。参考

二。给一定的钱 ,我们的购买方式是  应该先买M最大的物体(M=Q-P),然后依次买第二大、第三大、、、、、

         我们已经知道这个购买方式,怎么实现就要用到DP  中的0-1背包的思想了。

         dp[c]=max(dp[c],dp[c-p[i]])+v[i];   c 为第c 个物品。这是用一维数组实现01背包。。

         dp[c-p[i]] 是指   我们在容量为c 的包中 放了p[i]之后  还能放的物品的价值。

         i 从 1 到 n  。 dp[c-p[n]]  是放了 第n个物品后 还能放多少价值的物品。。。所以  P[n] 的M 值应该最大

        通俗的说: 这个dp过程 正好是逆向的  。   dp[c-p[i]]是dp[c]的最优子结构。

        所以 在DP 的时候我们应该按照 M的值从小到大排序。

       也就是说我们应该按照 Q-P 的值 从小到 大排序在 DP 了。。。。没看懂_(:з」∠)_

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;
int dp[5010];

int m;
int n;
//肯定要排序,但是如何排序呢?
//比如优先买价值最高的?
struct goods
{
    int p;
    int q;
    int v;
}g[N];
bool cmp(goods a,goods b)
{
    return (a.q-a.p)<(b.q-b.p);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        for(int i=1;i<=n;++i)
        {
            scanf("%d%d%d",&g[i].p,&g[i].q,&g[i].v);
        }
        sort(g+1,g+1+n,cmp);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;++i)
        {
            for(int j=m;j>=g[i].q;--j)
                dp[j]=max(dp[j],dp[j-g[i].p]+g[i].v);
        }

        printf("%d\n",dp[m]);
    }
    return 0;
}

hdu 3177 Crixalis's Equipment的题面和上面一题基本上差不多

区别是 Proud Merchants 要求M钱最多能获得多少价值  

Crixalis's Equipment要求V空间能否放下所有的Equipment

贪心策略:先搬差值大的

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;

int v;
int n;

struct equip
{
    int a;
    int b;
}e[N];
bool cmp(equip p,equip q)
{
    return (p.b-p.a)>(q.b-q.a);                         //差值大的先考虑
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&v,&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d",&e[i].a,&e[i].b);
        }
        sort(e+1,e+1+n,cmp);
        int flag=1;
        for(int i=1;i<=n;++i)
        {
            if(v>=e[i].b)
            {
                v-=e[i].a;
            }
            else
                flag=0;
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");

    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值