2007noip普及组 守望者的逃离

【题目描述】

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

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

输入
输入文件escape.in仅一行,包括空格隔开的三个非负整数M,S,T。

输出
输出文件escape.out包含两行:

第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 <= 10^8

【分析】

1.搜索

记忆化搜索即可,但是原则上,如果内存限制不够大的话30w的dfs会爆栈,这里不应该用dfs而应该用bfs…
先搜索出所有 f [ i ] [ j ] f[i][j] f[i][j] 的结果, f [ i ] [ j ] 表 示 第 i 秒 , 剩 余 蓝 量 是 j 能 走 的 最 远 距 离 f[i][j]表示第 i 秒,剩余蓝量是 j 能走的最远距离 f[i][j]ij,最后遍历整个 f 数组找一个最优解即可

#include<bits/stdc++.h>
using namespace std;
int m,s,t,ans,anstime;
int f[300105][15]={0};
void dfs(int nowtime,int way,int value){
	if (nowtime > t) return;        //若超出规定时间t则结束搜索
	if (f[nowtime][value] >= way) return;  //对当前状态判断是否比之前记录过的状态更优,若更优才继续搜索
	f[nowtime][value] = way;
	if (way >= s) return;     // 若当前移动的距离已经超过目标距离了,那么之后的搜索都是无意义的
	if (value >= 10){    //若当前蓝量足够闪烁,那么显然立刻闪烁是最优解
		dfs(nowtime+1,way+60,value-10);
	}
	else{
		//搜索移动和停止在原地回蓝两种状态
		dfs(nowtime+1,way,value+4);
		dfs(nowtime+1,way+17,value);
	}
}

int main() 
{
	memset(f,-1,sizeof(f));
	scanf("%d%d%d",&m,&s,&t);
 	int starttime = 0,start = 0;
	while (m >= 10 && starttime < t && start < s){
		//毋庸置疑,一开始将初始有的蓝全部用完
		m-=10;
		start+=60;
		++starttime;
	}
	//两个特殊情况,即蓝没用完,却已经逃离了,或蓝没用完,时间到了
	if (start >= s){
		printf("Yes\n%d",starttime);
		return 0;
	}
	if (starttime == t){
		printf("No\n%d",start);
		return 0;
	}
	dfs(starttime,start,m);
	int ans = 0;
	//在所有的状态中搜索一个最优解,若某次搜索发现已经逃离,那么当前时间就是最小时间
	for(int i = 1 ; i <= t ; ++i)
		for (int j = 0; j <= 14 ; ++j)
		{
			ans = max(ans,f[i][j]);
			if (f[i][j] >= s){
				printf("Yes\n%d",i);
				return 0;
			}
		} 	
 	printf("No\n%d",ans);
 	return 0;
}

2.dp

用F[t]表示守望者在t时间内所能走的最远距离,G[t]表示守望者只使用闪烁法术在t时间内所能走的最远距离。 则相应的状态转移方程为
{ F [ 0 ] = G [ 0 ] = 0 F [ t ] = m a x ( F [ t − 1 ] + 17 , G [ t ] ) \begin{cases} F[0] = G[0] = 0 \\ F[t] = max(F[t-1] + 17, G[t]) \end{cases} { F[0]=G[0]=0F[t]=max(F[t1]+17,G[t])

#include <stdio.h>

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

猜你喜欢

转载自blog.csdn.net/jnxxhzz/article/details/86669979
今日推荐