[洛谷P1095]NOIP2007 普及組T3 守望者的逃離
問題描述
惡魔獵手尤迪安野心勃勃,他背叛了暗夜精靈,率領深藏在海底的娜迦族企圖叛變。守望者在與尤迪安的交鋒中遭遇了圍殺,被困在一個荒蕪的大島上。為了殺死守望者,尤迪安開始對這個荒島施咒,這座島很快就會沈下去。到那時,島上的所有人都會遇難。守望者的跑步速度為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”(區分大小寫)時表示守望者能走的最遠距離。
樣例輸入輸出
樣例輸入#1
39 200 4
樣例輸出#1
No
197
樣例輸入#2
36 255 10
樣例輸出#2
Yes
6
提示
30%的數據滿足:1<=T<=10,1<=S<=100
50%的數據滿足:1<=T<=1000,1<=S<=10000
題解
一看數據範圍,用時間復雜度為O(n)的動態規劃比較合適。設f[i]表示時間為i時能走的最遠距離。實際上守望者每一天能夠選的操作只有3種:跑、閃爍和待在原地。但這三種狀態放在一起時會非常麻煩(在恢復魔法時還要考慮如果跑是否會更優,跑的時候也一樣)。不妨從動態規劃的局部最優性出發,既然要保證每一個狀態最優,那麽我們可以只存這個狀態中存的最優解,其他的如果不是最優就可以用更優的去更新它。所以假設只能用魔法跑一遍,再檢查每一個狀態從上一個狀態中轉移過來時選跑步是否更優。不用擔心會改變全局最優(因為只改變局部狀態)。只要找到一個狀態的距離超過s即滿足要求,輸出即可。
代碼
#include <iostream>
#include <cstdio>
#define N 300002
using namespace std;
int m,s,t,i,f[N];
int main()
{
cin>>m>>s>>t;
for(i=1;i<=t;i++){
if(m>=10){
f[i]=f[i-1]+60;
m-=10;
}
else{
f[i]=f[i-1];
m+=4;
}
}
for(i=1;i<=t;i++){
f[i]=max(f[i],f[i-1]+17);
if(f[i]>=s){
cout<<"Yes"<<endl<<i<<endl;
return 0;
}
}
cout<<"No"<<endl<<f[t]<<endl;
return 0;
}
[洛谷P1095]NOIP2007 普及組T3 守望者的逃離