这道题是一道非常明显的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通俗多了?????
什么,没有? 拉出去斩了
哈哈哈不存在的不存在的我那么和善(嘻~嘻~嘻~)