问题 1108: 守望者的逃离【Right】

时间限制: 1Sec 内存限制: 128MB

题目描述

  恶魔猎手尤迫安野心勃勃。他背叛了暗夜精灵,遂深藏在海底的那加企图叛变。守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上。为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很快就会沉下去,到那时,岛上的所有人都会遇难。守望者的跑步速度为17m/s, 以这样的速度是无法逃离荒岛的。庆幸的是守望者拥有闪烁法术,可在1s内移动60m,不过每次使用闪烁法术都会消耗魔法值10点。守望者的魔法值恢复的速度为4点/s,只有处在原地休息状态时才能恢复。
  现在已知守望者的魔法初值M,他所在的初始位置与岛的出口之间的距离S,岛沉没的时间T。你的任务是写一个程序帮助守望者计算如何在最短的时间内逃离荒岛,若不能逃出,则输出守望者在剩下的时间内能走的最远距离。
注意:守望者跑步、闪烁或休息活动均以秒(s)为单位。且每次活动的持续时间为整数秒,距离的单位为米(m)。
输入
输入仅一行,包括空格隔开的三个非负整数M,S,T。
输出
输出包含两行:
第1行为字符串"Yes"或"No" (区分大小写),即守望者是否能逃离荒岛。
第2行包含一个整数,第一行为"Yes" (区分大小写)时表示守望着逃离荒岛的最短时间
第一行为"No" (区分大小写) 时表示守望者能走的最远距离。
样例输入
39 200 4
样例输出
No
197
提示
30%的数据满足: 1 <= T<= 10, 1 <=S<= 100
50%的数据满足: 1 <= T <= 1000, 1 <= S <= 10000
100%的数据满足: 1 <= T <= 300000, 0 <= M<=1000 1 <=S <= 108

Codes & Analysis

初步判断,使用递归比较简便,但是我偏不用递归,可是真的好难啊!!
输入数据
M:剩余魔法数量
T:剩余时间
S:出口距离

可能的情况

1、能量足够完成逃脱
2、能量缺少一次恢复
3、能量缺少多次恢复
4、完成不了

思路零

正确的思路,结构简单,思路清晰,走一步看一步

在基本情况下,走一步回看一步。
设置三个记录标志:时间t,行走路程d、sum
注:行走路程d代表的是使用技能走的路程;sum表示综合行走路程,既包含魔法又包含奔跑路程

过程

对每一秒钟进行划分选择方式。
第一步:首先判断剩余能量是否足以施放技能:能则释放;不能,该时间用来恢复。
第二步:将该时间用来奔跑
第三步:综合sum,即单纯施放技能行走的路程是否大于释放技能完毕后不存储能量直接奔跑行走的路程
第四步:进行判断是否已经成功。

Codes0 Right!

#include
int main()
{
	int m, s, T, d = 0, t = 1, sum = 0;
	scanf("%d%d%d", &m, &s, &T);
	while (t <= T) {
		if (m >= 10) {
			d += 60;
			m -= 10;
		}
		else {
			m += 4;
		}
		sum += 17;
		if (sum < d)	sum = d;
		if (sum >= s) {
			printf("Yes\n%d", t);
			break;
		}
		else	t++;
	}
	if (t>T) {
		printf("No\n%d", sum);
	}
	return 0;
}

思路一

暂时这个思路是错误的,等我慢慢找BUG
真心烦

过程一

基本情况:恢复能量:4/s,奔跑速度:17m/s,技能位移:60m,技能施放时间:1s
在时间充足的情况下,进行三秒中的恢复外加一秒钟的施放技能时间,其能位移距离为60m,奔跑则为68m,此时奔跑性价比高
当仅用2s来恢复就能释放技能的时候,奔跑则为51m<60m,恢复性价比高。
所以得出当能量剩余>=2,且剩余时间>=3(能够有时间恢复能量且去释放技能)的时候,恢复性价比高
上述过程为循环,在循环的过程中判断是否能够安全脱离。

过程二

基本情况:当前距离:dist,总距离:s,当前时间剩余:t,总时间:T,过程一结果:剩余时间或者性价比不足以逃脱
用剩余的时间进行奔跑,并在循环的过程中进行判断是否能够成功逃脱

前提分析(性价比及条件情况)

1、仅花费一秒使用技能
速度:60m/s
条件:能量充足:m>=10;时间充足:t>0;
2、仅花费两秒使用技能
速度:60m/2s
条件:能量剩余>=6;时间剩余:t>=2;
3、仅花费3秒使用技能
速度:60m/3s
条件:能量剩余>=2;时间剩余:t>=3;
4、跑步
速度:17m/s
条件:时间剩余:t>0;

Codes1,Wrong

下面的代码错误情况为67%,错误原因有待分析

#include
int main()
{
    //m:magic   s:distance  t:time  interval=60m    v=17m/s
    //recover: 4/s  consume: 10/time
    int m,s,t,dist=0,flag=1,k,T;
    scanf("%d%d%d", &m,&s,&t);
    T=t;
    while(m>=6&&t>1&&flag){
        if(m<10){
            t--;
            m+=4;
        }
        dist+=60;
        m-=10;
        t--;
        if(!t)  flag=0;
        else if(dist>=s){//succeed
            flag=2;
            break;
        }
    }//magic is running out
    while(flag&&flag!=2){
        dist+=17;
        t--;
        if(!t)  flag=0;
        if(dist>=s) break;
    }
    if(flag)    printf("Yes\n%d", T-t);
    else    printf("No\n%d", dist);
    return 0;
}

代码更新片段:

while(m>=6&&flag){
	if(m<10&&t>1){
		t--;
       	m+=4;
   	}
	else if(m>=10){
		dist+=60;
		m-=10;
		t--;
	}
	else break;
	if(!t)  flag=0;
	if(dist>=s){//succeed
		flag=2; break;
	}
}//magic is running out

更新情况
第一:
原代码逻辑是将时间和剩余能量放在一起考虑,实际情况应将时间包含在剩余能量的考量中。
先将能量用完,进行恢复的时候需要判断剩余时间是否能够支持恢复。
除此之外,因为剩余时间和剩余能量的外层while判断是关于能量的,所以在进行释放能量的时候需要进行判断能量余额是否充足。
当两者均不满足时,使用else跳出循环
所以,使用if() else if() else格式
第二:
原代码中进行判断时间用完的情况和是否成功是if else格式的,实际上两者是相互独立地
时间刚好用完时能够成功逃脱,这是一种特殊情况,但是足以说明两者是独立的,并没有if else的关联

这是垃圾代码,错误的,思路不清晰
#include
int main()
{
    //m:magic   s:distance  t:time  interval=60m    v=17m/s
    //recover: 4/s  consume: 10/time
    int m,s,t,dist=0,flag=1,k,T;
    scanf("%d%d%d", &m,&s,&t);
    T=t;
    while(flag&&t){
        while(t>3&&flag){
            while(m>=10&&flag){
                dist+=60;
                m-=10;
                t--;
                if(!t)  flag=0;
                else if(dist>=s){//succeed
                    printf("Yes\n%d", T-t);
                    return 0;
                }
            }//magic is running out
            if(dist+17>=s){//not magic is quicker
                t--;
                printf("Yes\n%d", T-t);
                return 0;
            }
            else{
                t--;
                m+=4;//recover
            }
            if(!t){
                dist+=17;
                printf("No\n%d", dist);
                return 0;
            }
        }
    }
}

Codes2 Wrong

这个代码思路非常清晰,按照性价比来排序。但是仍然是错的,得再读读题目。

#include
int main()
{
	int m, s, t, d = 0,flag=1, T;
	scanf("%d%d%d", &m, &s, &t);
	T = t;
	//先使用性价比最高的能量
	while (m >= 10&&flag&&flag!=2){
		if (d >= s) {//succeed
			flag = 2;
			break;
		}
		if (!t) {//fail
			flag = 0;
			break;
		}
		t--;
		m -= 10;
		d += 60;
	}
	//再使用性价比其次的,即只需要2秒钟:1秒恢复,1秒释放技能,可以位移60m
	//此时m<10,d
	if (m >= 6 && t>=2 && flag && flag != 2) {//
		if (s - d <= 17) {//只需1秒,跑步走完全程
			t --;
			d += 17;
			flag = 2;
		}
		else {//花费时间:1s来恢复能量
			t--;
			m += 4;
			flag = 3;
		}
	}
	//接着使用性价比再其次的,只需要3秒钟:2秒恢复,一秒释放技能,位移60m
	//此时m<6,d
	if (m >= 2 && t >= 3 && flag && flag != 2) {//
		if (s - d <= 34) {//只需2秒,跑步走完全程
			t-=2;
			d += 34;
			flag = 2;
		}
		else {//花费时间:2s来恢复能量
			t-=2;
			m += 8;
			flag = 3;
		}
	}
	//对花费时间来恢复情况后的性价比最高,即花费1s来释放技能
	if (flag == 3) {
		t--;
		d += 60;
	}
	//最后使用性价比最低的,即17m/s的跑步,条件:t>=1
	while (t>=1&& flag && flag != 2) {
		t--;
		d += 17;
		if (d >= s)	flag = 2;
		else if (!t)	flag = 0;//未满足,且时间为0,失败
	}
	if (flag)    printf("Yes\n%d", T - t);
	else    printf("No\n%d", d);
	return 0;
}

你可能感兴趣的:(OJ练习)