1.题目链接。题目的大意就是给定一个迷宫,判定是否可以在规定的时间内从起点走到终点。这和一般的DFS有着一定的区别,这里我们不需要最短路,只需要一条最合适的道路,因为这个门的打开是在规定时间打开的,去早了也不行,去晚了也不行,所以所以这里我们需要找到一条合适的路。这个体现程序中也就是我们在搜索的过程中需要加上判断的条件。
2.分析:其实这个问题不是很困难,搜索就是一种优雅的暴力嘛,我们只需要把每一条可行的路径的时间计算,然后判断是否可行即可。显然,这是需要减支的,否则就会T掉。关于这个题的减支,很多博客都提出了奇偶减支,但是很少有说明为什么的,这里我就来解释一下,当然大佬们不写并不是不会,只是觉得显然的事情,没有必要再浪费口舌。
3.减支:我觉得这个题的减支可以分为三个方面。
(1)普通的剪枝:这个很显然了,这个也就是dfs的出口,这个估计大家都会写。就是在搜索的过程中,首先应该判断坐标的合法性,当前已经走了多少步,是否还有时间等等一些细节的问题。局部的代码大概如下
if(x<0||x>=n||y<0||y>=m)
return;
if(time>t||(time==t&&(ex!=x||ey!=y)))
{
flag=false;
return ;
}
if(ex==x&&ey==y&&time==t)
{
flag=true;
return ;
}
if(flag)
return;
(2)全局的剪枝:这个应该叫做先决条件,或者可以开始搜索的必要条件。这个条件就是:m*n-wall<=t.其中m和n是这个图的大小,wall是这个图中X的数量,t是规定的时间。为什么会有这个条件,其实这个不等式就是在告诉我们这样的信息,你这个图剩下的可以行走的点要足够我t时间内走过的。什么意思,我想大家应该应该很明白了,就是说我有t秒的时间,那么我在这t秒的时间内一定是需要走过t个点的,你这个图给我留下的空间要足够,否则我t秒需要走t个点,但是你图中只有t-1点,这显然是不行的。然后就是相等的条件,为什不是小于而是小于等于?因为起点的原因。
(3)然后就是最重要的奇偶剪枝了,这个我们上边就说了,很多博客也提过了,但是很少有说明为什么的。我先给出结论:从起点到达终点的最短路径和从当前点到达目标点路径长度同奇偶(这里的长度我们定义为走过的格子的数量),其实这个就是哈密尔顿距离。为什么是这样的,我们首先来思考一个问题,最短路径,那就是直接不考虑障碍物的时候,起点到终点的的横纵坐标之差,假设我们在行走的过程总有障碍物,那么我们要绕开它,由于我们不能沿着对角线行进,那么我们只能避开这个障碍物,我们只能绕行,这个绕行就是一次两个格子,所以其实最短的路径和我们真实路径永远都是相差2k的,所以二者同奇偶。
知道了这些剪枝,下边的代码就很好写了。我始终坚信,程序是一个很确定的东西,不能有半点模糊。下面是代码:
#include<bits/stdc++.h>
using namespace std;
char a[10][10];
int n,m,t;
int sx,sy,ex,ey;
bool flag;
int dir[4][2]={1,0,0,1,0,-1,-1,0};
void DFS(int x,int y,int time)
{
if(x<0||x>=n||y<0||y>=m)
return;
if(time>t||(time==t&&(ex!=x||ey!=y)))
{
flag=false;
return ;
}
if(ex==x&&ey==y&&time==t)
{
flag=true;
return ;
}
if(flag)
return;
int temp=(t-time)-(abs(x-ex)+abs(y-ey));
if(temp<0||temp&1)
return;
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(a[xx][yy]!='X')
{
a[xx][yy]='X';
DFS(xx,yy,time+1);
a[xx][yy]='.';
if(flag)
return ;
}
}
}
int main()
{
while(cin>>n>>m>>t)
{
if(n==0&&m==0)
break;
int wall=0;
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
{
cin>>a[i][j];
if(a[i][j]=='S')
sx=i,sy=j;
else if(a[i][j]=='D')
ex=i,ey=j;
else if(a[i][j]=='X')
wall++;
}
if(n*m-wall<=t)
{
cout<<"NO"<<endl;
continue;
}
flag=false;
a[sx][sy]='X';
DFS(sx,sy,0);
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}