问题链接:Problem G
问题简述:
给出一幅地图,已知狗的起点S,终点门D的坐标,门只在时间t开启,而狗每次移动后,以前踏过的地板便会下沉消失(即不能走重复的路),问狗能否在指定的时间T到达门。
问题分析:
此题并非求最短路径,因此用BFS并不合适,因BFS同时向多条路径并发,容易影响到其他路径的方向导致答案错误,若不标记路径,又容易队列过长而TLE,因此DFS会更适合该题。但光用DFS,由于其每次搜索都会遍历全图的特性,会导致TLE,因此需要剪枝。
- 第一次剪枝:当步骤数已经大于时间T时,不需要再进行搜索
- 第二次剪枝:当已经找到答案时,不需要再进行搜索
- 第三次剪枝比较复杂,我们先将map以0,1编号;
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
可见0走奇数步只能到1,走偶数步只能到0.可见四个方向行走的地图具有“奇偶性”,其奇偶性为点坐标相加对 2取余。
因此第三次剪枝可为:当S与D的奇偶性相同时,若t为奇数,则不能走,当S与D的奇偶性不同时,若t为偶数,则也不能走。
至此问题已经解决。
AC通过的C++语言程序如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
char map[10][10];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
bool vis[10][10];
int n,m,t;
bool flag;
bool edge(int x,int y){
if(x>=0&&y>=0&&x<n&&y<m&&map[x][y]!='X'&&vis[x][y]==0){
return 1;
}
else{
return 0;
}
}
void DFS(int x,int y,int step){
if(map[x][y]=='D'&&step==t){
flag=1;
return;
}
if(step>t){
return;
}
for(int i=0;i<4;i++){
int next_x=x+dir[i][0];
int next_y=y+dir[i][1];
if(edge(next_x,next_y)){
vis[next_x][next_y]=1;
DFS(next_x,next_y,step+1);
vis[next_x][next_y]=0;
if(flag){
return;
}
}
}
}
int main(){
std::ios::sync_with_stdio(false);
while(cin>>n>>m>>t){
if(!n&&!m&&!t){
break;
}
flag=0;
memset(vis,0,sizeof(vis));
int sx,sy,dx,dy;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>map[i][j];
if(map[i][j]=='S'){
sx=i;
sy=j;
}
if(map[i][j]=='D'){
dx=i;
dy=j;
}
}
}
int ps=(sx+sy)%2;
int pd=(dx+dy)%2;
int pt=t%2;
if(ps!=pd&&!pt){
cout<<"NO"<<endl;
continue;
}
else if(ps==pd&&pt){
cout<<"NO"<<endl;
continue;
}
vis[sx][sy]=1;
DFS(sx,sy,0);
if(flag){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
}