Escape解题报告 - 提前计算对于程序的帮助 - 贪心算法与动态规划

这个世上有那么一种题目,只需要将数据分类就万分简单,只需要几十行的程序就可以解决,随便蒙一下还能拿个三四十分。这种题目,这里就有一道。

4.守望者的逃离(escape)

【问题描述】

恶魔猎手尤迫安野心勃勃.他背叛了暗夜精灵,率深藏在海底的那加企图叛变:守望者在与尤迪安的交锋中遭遇了围杀.被困在一个荒芜的大岛上。为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很快就会沉下去,到那时,岛上的所有人都会遇难:守望者的跑步速度,为17m/s, 以这样的速度是无法逃离荒岛的。庆幸的是守望者拥有闪烁法术,可在1s内移动60m,不过每次使用闪烁法术都会消耗魔法值10点。守望者的魔法值恢复的速度为4/s,只有处在原地休息状态时才能恢复。

现在已知守望者的魔法初值M,他所在的初始位置与岛的出口之间的距离S,岛沉没的时间T。你的任务是写一个程序帮助守望者计算如何在最短的时间内逃离荒岛,若不能逃出,则输出守望者在剩下的时间内能走的最远距离。注意:守望者跑步、闪烁或休息活动均以秒(s)为单位。且每次活动的持续时间为整数秒。距离的单位为米(m)

【输入格式】

输入数据仅一行,包括空格隔开的三个非负整数MST

【输出格式】

输出数据包含两行;

1行为字符串“Yes”或“No (区分大小写),即守望者是否能逃离荒岛;

2行包含一个整数,当第一行为“Yes(区分大小写)时表示守望着逃离荒岛的最短时间 ,当第一行为“No (区分大小写) 时表示守望者能走的最远距离。

【输入输出样例】

 

输入

输出

样例1

39 200 4

No

197

样例2

36 255 10

Yes

6

【数据规模】

30%的数据满足: 1≤T≤10 1≤S≤100

50%的数据满足: 1≤T≤1000 1≤S≤10000

100%的数据满足: 1≤T≤300000 0≤M≤1000 1≤S≤10^8


初看来,这道题的数据范围很大,而且涉及到了大量的决策问题,很容易划分阶段(以时间作为阶段),不像其他的一些坑题,还给你来个什么闪要7秒、走要6秒、等要5秒的,而且闪只需攒够魔力,不像其他的某些题,必须在等之后马上闪,有些浪费了。这就得出了我们的动态规划策略:首先将能用的魔力全部用光(显然要这样),然后判断在剩下来的路程中是等好还是走好(相当于把两个人放到同一个起跑线上,一个人尽量走,一个人尽量闪),接着再逐一作出决策。这个方法是我做完之后想到的,看到数据范围……爆空间。不过看到网上的方法有说可以用滚动数组的。

但是,动态规划还是有些慢了,想也要想半天。于是,我就用了这么一种方法:贪心!首先,我们寻找一下数量关系的规律,可以发现有以下几个要点:

1.一开始要尽量用掉魔法值,这样才能走最远的距离;

2.如果剩余距离大于102(即17*6,第一个走路和等待加闪有区别的地方,小于等于102的时候都是直接用走就行了),且剩余时间足够(时间至少为7),则等待五次再闪两次;

3.若有两点及两点以上,五点及五点以下,且剩余距离大于34(17*2,当只用等待两次,剩余距离大于34,都是等待并闪好),且剩余时间足够(时间至少为3),就等待两次,再闪。

4.若有6点及6点以上,且剩余时间足够(时间至少为2),剩余距离大于17(17*1,当只用等待一次,剩余距离大于17,都是等待并闪好),就等待一次并闪。

5.其他情况,直接走。为什么呢?首先,有的时候时间不够,直接走显然比站在原地干等好,再说了,等也没有什么用,时间不够就凑不够。还有一些情况,直接走的距离反而更长。

这就是我所总结出的贪心要点,相信这样也能看懂我的程序了吧。

 
     
 
     

#include
#include
using namespace std;
int Mana, Space, Timeleft;
int main()
{
freopen("escape.in", "r", stdin);
freopen("escape.out", "w", stdout);
scanf("%d %d %d", &Mana, &Space, &Timeleft);
int SpaceHaveSpend = 0, TimeHaveSpend = Timeleft;

while(Mana >= 10 && Timeleft > 0 && Space - SpaceHaveSpend > 0) //有魔法直接用
{
if(Space - SpaceHaveSpend > 17)
{
SpaceHaveSpend += 60;
Mana -= 10;
Timeleft--;
}
else printf("Yes\n%d", TimeHaveSpend - Timeleft - 1); //若魔法用完后直接到达,则结束
}

while(Timeleft > 0 && Space - SpaceHaveSpend > 0)
{
if((Mana == 0 || Mana == 1) && Timeleft >= 7 && Space - SpaceHaveSpend > 102)
{
Timeleft -= 7; //等五次,闪两次,
SpaceHaveSpend += 120;
}
else if(Mana >= 2 && Mana <= 5 && Timeleft >= 3 && Space - SpaceHaveSpend > 34) //等两次,闪一次
{
Mana -= 2;
Timeleft -= 3;
SpaceHaveSpend += 60;
}
else if(Mana >= 6 && Timeleft >= 2 && Space - SpaceHaveSpend > 17) //等一次,闪一次
{
Mana -= 6;
Timeleft -= 2;
SpaceHaveSpend += 60;
}
else
{
SpaceHaveSpend += 17; //其他情况直接走
Timeleft--;
}
}

if(Space <= SpaceHaveSpend) printf("Yes\n%d", TimeHaveSpend - Timeleft); //输出答案
else printf("No\n%d", SpaceHaveSpend);

return 0;
}


当然,动态规划也不是不行,但是动态规划还要多想想,还要一些贪心优化一下,还要滚动数组,感觉没有一个贪心简单。


你可能感兴趣的:(题解收集)