题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1010
题目大意:一只小狗被困在一个n*m的迷宫里,现在处在 ‘S’ 位置,判断其能否在 ‘T’ 秒是刚好到达出口 ‘D’,且走过的位置不能重复(这里要注意是刚好在 ‘T’ 时到达出口位置)
很明显这题应该用深搜来遍历,并且需要用到剪枝,不然面对指数级的遍历大概率会超时。但是令我没想到的时,这道题要剪很多次枝,要用到的最重要的就是奇偶性剪枝
这里简单的介绍下几次可以剪枝的地方:
①:在数据输入后,可先判断所有剩余可走的格子数量是否大于时间T大小。这里可以先思考由于1秒走1步,所以 T秒正好到达出口 应该对应的就是 到出口一共要走T步,所以小狗必须走慢T格,这个迷宫能走的位置内连T格都没有,因为走过的路就不能走了,那肯定不满足条件,直接筛掉。当然这一步只是粗略的判断,这一步无法筛去那些减去不连通(被墙挡住)的格子的数量小于T的情况。
if(n*m-1-x<T){ 那些能走的格子还要排除‘S’,所以减1。
cout<<"NO"<<endl;
continue;
}
②:如果DFS过程中当前步数以前超过T,但还没到,直接retrun;
③:如果当前剩余T-cnt秒(步)能走,而T-cnt比 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门都小,说明肯定来不及。
④:最关键的剪枝:奇偶性剪枝
先了解下它:
图片转自: https://blog.youkuaiyun.com/yinghui_yht/article/details/52971849
我们可以从上述结论中可以推理:如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门)
的距离为奇数,那么两个点肯定是 1-0 或者0-1的关系,又因为上述01or10奇数步结论,小狗不管怎么走走到出口这个距离肯定是奇数,剩余的步数T如果是偶数的话两者肯定不会相等,所以T必须为奇数。小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为偶数时反之。
简而言之:如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为偶数,那么不管小狗怎么走肯定需要花偶数步来到达T;如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为奇数,那么不管小狗怎么走肯定需要花奇数步来到达T。
因此我们这里可以直接来判断,并且结合 ③ 的技巧一起判断。
int temp=T-cnt-abs(x-d.x)-abs(y-d.y); d.x和d.y即出口的坐标,x和y是小狗现在处在位置的坐标
if(temp&1||temp<0) return;
ACcode:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
struct node{
int x,y;
};
node s,d; s是小狗开始所在的位置,d是出口的位置
char maze[10][10];
int D[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
bool f;
int n,m,t;
void dfs(int x,int y,int cnt){
if(cnt>t) return; 剪枝2
int temp=t-cnt-abs(x-d.x)-abs(y-d.y);
if(temp&1||temp<0) return; 剪枝3,4
if(cnt==t&&x==d.x&&y==d.y){
f=1;
return;
}
node now;
for(int i=0;i<4;i++){
if(f) return;
now.x=x+D[i][0];
now.y=y+D[i][1];
if(now.x<1||now.x>n||now.y<1||now.y>m||maze[now.x][now.y]=='X') continue;
maze[now.x][now.y]='X';
dfs(now.x,now.y,cnt+1);
maze[now.x][now.y]='.';
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
while(cin>>n>>m>>t,(n+m+t)){
int x=0;
f=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>maze[i][j];
if(maze[i][j]=='S'){
s.x=i;
s.y=j;
}
if(maze[i][j]=='D'){
d.x=i;
d.y=j;
}
if(maze[i][j]=='X') x++;
}
}
maze[s.x][s.y]='X';
if(n*m-1-x<t){ 剪枝1
cout<<"NO"<<endl;
continue;
}
dfs(s.x,s.y,0);
if(f) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}