Problem :
在某个盛夏之夜,桑海之滨,zhexipinnong仰望着星空,皎洁的月光,凉爽的海风......突然, 啊! Help me!! Help! .....H..e...l.....p.......。 zhexipinnong被潮汐卷走了。
另一个故事又开始了: little_w家在一个H x W的网格型(每个格子大小为10 x 10m)的坎坷的沙滩上,坐标为(X,Y),她喜欢在沙滩上散步。有这么一些规则:
①每个格子的高度是固定的,海潮随时间变化,可近似为:v = meter , t 单位为second。 其中a是随季节变化的系数。
②little_w只会走退潮后晒了至少1 hour的地方,且只能往东南西北四个方向走,当然也可以在原地享受。
③little_w走向的位置和当前位置高度差不能超过1 meter,从一个格子走向另一个格子时需用时m second , 且整个过程中两块区域都必须是晒干了的。
④little_w自由活动时间只有12hour,因为little_mother会叫她回家吃饭。
现在little_w想知道她能到达且可以按时回家的位置距离她家最多有多少meter? 计算时以格子中心为标准。
Input:
First line : a m // 0.0<a<15.0 , 0.1<=m<=60.0
Second line: W H X Y // 1<=W,H<=200.
Follow H lines each containing W integers, describing the height in millimetres. // 0<=h<=20000.
Output:
Little_w 能到达的最远位置离她家的距离(meter)。
Solution:
难点:(1)篇幅很长,英语阅读理解能力。
(2)怎样判断一个点是否可达,并能按时安全返回?
整体思路是比较每个点最早能到达的时刻arrive[i]和最晚必须离开的时刻left[i] , 若arrive[i] <= left , 则可以走到第i点,并按时返回。为什么呢?
分析:从y=的图形可看出:如果能够待在某个点,一定是一个完整的时间段。因此: 如果在arrive[i]和left[i]两个时刻待在第i点是可行的,且arrive[i] <= left[i] ,那么在arrive[i]和left[i]之间的任意时刻都是待在第i个点上都是安全的。
时间单位统一为 s , 高度单位统一为 mm.
我们可以先算出每个点没被海水淹没的时间段:
开始 : Ta = 6.0*3600/pi * acos(2.0*h/a - 1.0)
结束 : Tb = 12*3600 - Ta.
然后从(X,Y)在0时刻做一次单源最短路可求得arrive[].
从(X,Y)在12*3600时刻做一次逆向的单源最短路可求得left[i].
具体细节参考代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <cstdlib>
#include <cassert>
using namespace std;
typedef long double LD ;
const int maxn = 205 * 205;
const LD INF = (LD)1e10 ,eps = (LD)1e-8 , pi =(LD) acosl(-1.0) ;
const int dx[] = {0,-1,0,1};
const int dy[] = {1,0,-1,0};
int sig(LD x){ return (x>eps) - (x<-eps) ; }
struct Edge{
int from,to ;
LD L , R ;
Edge(){};
Edge(int a,int b,LD l,LD r):from(a) , to(b) , L(l) ,R(r){};
};
LD a , m ;
int W , H , X , Y ;
LD height[maxn];
LD Ta[maxn] , Tb[maxn] ;
LD arrive[maxn] , left[maxn];
vector<int>G[maxn];
vector<Edge>edges;
void add_edge(int u,int v,LD l,LD r){
edges.push_back(Edge(u,v,l,r)) ;
G[u].push_back(edges.size() - 1);
}
inline int ID(int a ,int b){
return a*W+b ;
}
inline LD cal_time(LD h){ // milimetres , return second
if(h > a) return -INF ;
return 6.0*3600/pi * acosl(2.0*h/a - 1.0) ;
}
void build_graph(){
for(int i=0; i<H ;i++) for(int j=0; j<W ;j++){
int id = ID(i,j) ;
arrive[id] = INF , left[id] = -INF ;
LD t = cal_time(height[id]) ;
Ta[id] = t , Tb[id] = 12.0*3600 - t ;
}
for(int x=0; x<H; x++) for(int y=0; y<W;y++) for(int d=0;d<4;d++) {
int nx = x+dx[d] , ny = y+dy[d] ;
int u = ID(x,y) , v = ID(nx ,ny) ;
if(nx<0 || nx>=H || ny<0 || ny>=W) continue ;
LD low = max(Ta[u]+ 3600.0 , Ta[v]+ 3600.0) ;
LD high = min(Tb[u]-m , Tb[v]-m);
if(low <= high && fabsl(height[u]-height[v])<=1000.0 )
add_edge(u,v,low,high);
}
}
void cal_min_arrive_time(){
int s = ID(X ,Y) ;
bool inq[maxn] = {0};
memset(inq ,0 ,sizeof(inq)) ;
queue<int>Q ;
Q.push(s) , arrive[s] = 0.0 , inq[s] = true ;
while(!Q.empty()){
int u = Q.front(); Q.pop() , inq[u] = false ;
for(size_t i=0; i<G[u].size(); i++){
Edge &e = edges[G[u][i]] ;
if(arrive[u] > e.R) continue ; // 若arrive[u]<e.L 可以等一会儿,但arrive[u]>e.R不可行。
LD reach_time = max(arrive[u] , e.L) + m ;
if(reach_time < arrive[e.to]) {
arrive[e.to] = reach_time ;
if(!inq[e.to]) Q.push(e.to) , inq[e.to] = true ;
}
}
}
}
void cal_max_left_time(){
int s = ID(X ,Y) ;
bool inq[maxn] = {0};
queue<int>Q ;
Q.push(s) , left[s] = 12.0 *3600 , inq[s] = true ;
while(!Q.empty()){
int u = Q.front(); Q.pop() , inq[u] = false ;
for(size_t i=0; i<G[u].size(); i++){
Edge &e = edges[G[u][i]] ;
if(left[u] < e.L) continue ;
LD reach_time = min(left[u] , e.R) - m ;
if(reach_time > left[e.to]) {
left[e.to] = reach_time ;
if(!inq[e.to]) Q.push(e.to) , inq[e.to] = true ;
}
}
}
}
LD cal_best(){
LD ret = (LD)0;
for(int x=0; x<H ;x++) for(int y=0; y<W; y++) {
int t = ID(x,y);
if(arrive[t] <= left[t]) ret = max(ret , (LD)0.0+(x-X)*(x-X) + (y-Y)*(y-Y)) ;
}
return ret ;
}
int main()
{
// freopen("e:in.txt","r",stdin) ;
scanf("%Lf%Lf", &a, &m) ; a*=1000 ;
scanf("%d%d%d%d" ,&W ,&H ,&Y ,&X) ;
for(int i=0; i<H; i++)
for(int j=0; j<W ; j++)
scanf("%Lf" ,&height[ID(i,j)]);
build_graph() ;
cal_min_arrive_time();
cal_max_left_time() ;
LD ans = cal_best() ;
printf("%.8Lf\n" , 10.0 * sqrtl(ans));
return 0;
}