守望者的逃离——关于这道题的思考

文章讲述了如何用一维时间数组表示状态并采用贪心策略解决逃跑问题。关键在于在魔法值小于10时动态权衡跑步和休息的选择,以及理解魔法值带来的最优策略具有延迟性。作者通过代码解释了动态比较的重要性以保持整体最优解。
摘要由CSDN通过智能技术生成

题目

个人思考

问题一:状态的表示问题

对于这道题我们可以用一维数组来存储状态,我首先考虑的是用数组存储距离,因为考虑到有的一次路程是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的情况下得到后面的最优,而不是选择跑步。

现在再看一下上面那个困惑,是不是恍然大悟了呢。

由于到底哪种选择最优,我们在当时的时刻是得不出结果的,只有同时保存两种情况的值,在每一个时刻都去比较一次,这种动态的比较才能保持整体的最优。

我的理解到此结束一段落了,我修改了好几遍措辞希望能讲清楚。其实最好的办法是自己模拟一遍代码的过程,这样更加直观。

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值