Description:
有一个
n
⋅
m
n\cdot m
n⋅m的字符矩阵,其中
′
M
′
'M'
′M′为起点,
′
D
′
'D'
′D′为终点,
′
T
′
'T'
′T′为障碍,
′
H
′
'H'
′H′为敌人起点,敌人会在每一时刻扩散到周围4格,而你没一时刻最多可以移动
S
S
S格,求最迟可以在哪个时刻出发且安全到终点。
n
,
m
≤
800
n,m\le 800
n,m≤800
Solution:
- 很显然我们可以二分答案,而关键就在check(
实际就是模拟题) - 我们先用 b f s bfs bfs求出敌人到达其它点的最小时间
- 再就是从起点模拟,注意比较符号,题中是人先走,敌人再走
- 这样复杂度为 Θ ( n 2 log ( n 2 ) ) \Theta(n^2\log (n^2)) Θ(n2log(n2))
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
const int N=802,INF=0x3f3f3f3f;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int n,S;
char mp[N][N];
int t[N][N];
struct node{
int x,y;
}M;
queue<node>Q;
int vis[N][N];
bool check_xy(int x,int y){return x<1 || x>n || y<1 || y>n;}
bool check(int tim) {
if(tim>=t[M.x][M.y]) return 0;
while(!Q.empty()) Q.pop();
memset(vis,INF,sizeof(vis));
vis[M.x][M.y]=tim*S;
Q.push((node){M.x,M.y});
while(!Q.empty()) {
node now=Q.front();Q.pop();
if(mp[now.x][now.y]=='D') return 1;
REP(i,0,3) {
int nx=now.x+dx[i];
int ny=now.y+dy[i];
if(check_xy(nx,ny))continue;
if(mp[nx][ny]=='T')continue;
if(vis[nx][ny]==INF && (vis[now.x][now.y]+1)/S<t[nx][ny]) {
vis[nx][ny]=vis[now.x][now.y]+1;
Q.push((node){nx,ny});
}
}
}
return 0;
}
int main() {
// freopen("mecho.in","r",stdin);
// freopen("mecho.out","w",stdout);
scanf("%d%d",&n,&S);
REP(i,1,n) scanf("%s",mp[i]+1);
memset(t,INF,sizeof(t));
REP(i,1,n) REP(j,1,n) {
if(mp[i][j]=='H') t[i][j]=0,Q.push((node){i,j});;
if(mp[i][j]=='M') M=(node){i,j};
}
while(!Q.empty()){
node now=Q.front();Q.pop();
REP(i,0,3){
int nx=now.x+dx[i];
int ny=now.y+dy[i];
if(check_xy(nx,ny))continue;
if(mp[nx][ny]=='T' || mp[nx][ny]=='D')continue;
if(chkmin(t[nx][ny],t[now.x][now.y]+1)) Q.push((node){nx,ny});
}
}
int L=0,R=n*n,ans=-1;
while(L<=R){
int mid=(L+R)>>1;
if(check(mid)) ans=mid,L=mid+1;
else R=mid-1;
}
printf("%d\n",ans);
return 0;
}