题目
个人思考
问题一:状态的表示问题
对于这道题我们可以用一维数组来存储状态,我首先考虑的是用数组存储距离,因为考虑到有的一次路程是17m/1s,有的是60m/2s等等,时间不一定是按1s跳动来比较的。
后来发现这样写很麻烦,难以实现各种逃离措施的比较,还不如按时间。
所以我决定采取时间作为一维数组表示的量。我们采用贪心策略,在每一秒时刻都试图实现逃离最远的路程。
问题二:如何比较
在每一个时间,我们有三种状态可以选择。
一是跑步17m,魔法值+0
二是闪烁60m,魔法值-10
三是休息0m,魔法值+4
很显然,如果魔法值>=10,最优选择二。
如果小于10呢?如何衡量哪个最优呢?
我们的核心问题是在小于10情况下,选择跑步or休息,才能实现整体最优。
这个时候我的建议是动态的去权衡。在遍历t的时候,我们记录两个距离,可以令为a和b。a存储下一步选择跑步17m的最大距离。b存储下一步选择闪烁或者休息的最大距离。在每一轮都对a和b进行比较,将最大值保存下来赋给a。a就是最优逃离策略下产生的距离。
#include<bits/stdc++.h>
using namespace std;
int m,s,t,a,b;
int main(){
cin>>m>>s>>t;
for(int i=1;i<=t;i++)
{
a+=17;//每一时刻都选择跑步
if(m>=10)
{
b+=60;
m-=10;
}
else
m+=4;
a=max(a,b);//如果发现闪烁和休息组合情况更优,替换为这种更优情况
if(a>=s)
{
cout<<"Yes"<<endl;
cout<<i;
return 0;
}
}
cout<<"No"<<endl;
cout<<a;
return 0;
}
对应代码如上,我想如果你思考了这段代码,可能会产生一个困惑,在a=max(a,b)处的比较赋值代码,说明了我们在这个时间段选择了其中一种方法产生的最值,那为什么不需要把其他方法中被我们修改的魔法值m复原呢?
因为m值带来的最优策略具有延迟性,它可能在后面几步才体现自己的优势。我们可以完全不碰b值,不修改它。如果t已经结束,还没有体现m值带来的最优策略,那完全ok的,说明剩下时间不够我们去积攒魔法值闪烁了,那我们更改的m值也不会出现在输出结果里。如果t没有结束,体现了m值带来的最优策略,那么正合我们意,将方法又跑步修改为积攒魔法再闪烁a=max(a,b),即a=b。
这恰恰是我所说的动态权衡的地方。
我们应该意识到,我们在这次选择下抛弃的方法确实是修改了m,但是因此产生的结果仍然存在变量b里,一旦在后面几步发现a=max(a,b)得到的是a=b,那么说明这次选择就是在修改m的情况下得到后面的最优,而不是选择跑步。
现在再看一下上面那个困惑,是不是恍然大悟了呢。
由于到底哪种选择最优,我们在当时的时刻是得不出结果的,只有同时保存两种情况的值,在每一个时刻都去比较一次,这种动态的比较才能保持整体的最优。
我的理解到此结束一段落了,我修改了好几遍措辞希望能讲清楚。其实最好的办法是自己模拟一遍代码的过程,这样更加直观。