luoguP1048题解 && 对dp和贪心的一点个人理解

这道题是一道非常明显的01背包

那么我们来看

题目给定了上山的总时长,我们怎么在规定的时间内找到使价值最大的方案呢

方案一:我们来考虑一下性价比的问题,即药品的价格与采摘时间的比值。

显然,这种做法基本0分,那么,为什么呢?

代码贴上:

#include<bits/stdc++.h>
using namespace std;
int T,M;
int a[5212];
int c[5212];
int val[5212];
int v[5212];
int t;
int ans;
int toto;
int main(){
    cin>>T>>M;
    for(int i=1;i<=M;i++){
        cin>>a[i]>>c[i];
        val[i]=c[i]/a[i];
        v[i]=c[i]%a[i];
    }
    for(int i=1;i<=M;i++){
        if(val[i]<val[i+1]){
            swap(val[i],val[i+1]);
            swap(c[i],c[i+1]);
            swap(a[i],a[i+1]);
        } 
    }
    for(int i=1;i<=M;i++){
        toto+=c[i];
        if(toto<=T){
            ans+=a[i];
        }
        else break;
    }
    cout<<ans<<endl;
    return 0;
}

这里我们就要上一组数据:

100 3

60 10 1

20 5 2

100 100 3

这样我们就能证明我们刚才的结论了: 如果我们依然使用性价比的思想,那么我们来看

显然val[1]=6,val[2]=4,而val[3]=1。 也就是说,如果我们依然使用性价比排序,我们最终会因为时限不够而错过真正意义上“性价比”最大的3号 这时我们就应该想到,显然这种贪心的做法不是最优解,那除了贪心就是dp了呗。

那我们就来看一下dp的做法,这边的话大家可以先看我的代码找一下方程然后自己理解一下,个人建议思考2分钟左右再看我下面的讲解……

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
int dp[1050][1050];
int w[150],v[150];      
int t,m;
int dfs(int i,int j)
{
    if(dp[i][j]>=0) return dp[i][j];
    int res;
    if(i==m+1) res=0;
    else if(j<w[i]) res=dfs(i+1,j);
         else res=max(dfs(i+1,j),dfs(i+1,j-w[i])+v[i]);   
    return dp[i][j]=res;   
}
int main()
{
    memset(dp,-1,sizeof(dp));//虽然我记得memset只能赋0,但是没想到别的就这么用了,居然真过了……
    cin>>t>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>w[i]>>v[i];
    }
    cout<<dfs(0,t);
    return 0;                                                                                                       
}

所以,看完辣的小伙伴们我们来看一下这个方程是怎么出来的: 我们要找到最优解,那么dp的思维肯定是对每一步都求最优解,而且dp的特点就是连续性(我自己起的),我们对dfs中的i定义为当前的药品序号,j定义为当前剩余的时间。

我们来看,我们要选取规定时间内采取的最大价值,我们就要考虑,当我们认定下一种情况被选取,即我们假定采摘下一种药品时,将不猜这种药品的结果与采摘这种药品的结果进行对比,所以方程自然是

max(dfs(i+1,j),dfs(i+1,j-w[i])+v[i])

我们来对方程进行一下解释:方程的前半部分,我们考虑了不采摘这种药品的情况,这时,不需要考虑消耗的时间,也无法得到采摘这种药品产生的价值,但是我们的状态要转移到这一种药品上来,说明我们对这一药品进行了“不采摘”的操作;方程的后半部分,我们考虑了采摘这一药品的情况,这时,一样的道理,我们可以得到dfs(i+1,j-w[i])+v[i]的式子(这个这么简单就不说了吧)


所以,其实啊,这道题很水,真的很水

可能只有我这种蒟蒻来发题解(当然不乏大佬来虐场)

本人有生之年最长的一篇题解,真是累死宝宝了呢~


那么说了这么多,最后还是要对贪心和dp说点什么哈~

贪心嘛,顾名思义,是我们日常生活中最常见的一种思维方式,举个栗子,我们参加比赛,总是最想得到一等奖(假如有奖金),如果你可以参加很多比赛,而你又不会分身术,这个问题就变成了区间问题,如果你会分身术的话(那您真是太强辣!!!),这不就是一个贪心的很好的栗子,你一定会参加最多的比赛,越多越好,没有人会佛到有钱不赚吧……(反正本蒟蒻是不会,因为我比较俗),这就是贪心的基本思维,每一步都求最优解。

---------------------------------------------------------------------------------------------------------------

(以上是自制分隔线)

那么,dp又是什么呢?

就是我们上面题中讲到的,如果我们不会分身术,每项比赛的难度又不一样,换言之,我们拿一等奖的概率不同,我们在进行报名之前就要在心里做一下规划,怎样报名比赛才可能获得最多的奖金,这时,我们就要考虑很多问题,比如,我们首先要考虑我们可能参加多少比赛?  其次,我们要考虑我们参加最多的比赛可不可能拿到最高奖金?   诸如此类,有很多问题,我们需要在这些问题中找到一个通用的规律,以便于我们求从开始决策到目前的状态所能得到奖金的最大值(有的问题当然是最小值辣)。

 

我跟男噶就降到了dp最基本的思路,我把它理解为“求从开始决策到目前状态区间内的最优解”

刚才说的规律也就是我们所说的“状态转移方程”

怎么样,这么看的话是不是感觉dp通俗多了?????

什么,没有?       拉出去斩了

哈哈哈不存在的不存在的我那么和善(嘻~嘻~嘻~)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oblivion_Zzz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值