#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char map[10][10];
int visit[10][10];
int n, m, t;
int sx, sy, ex, ey;//记录起点和终点
int dir[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };//表示行走的方向
bool flag = false,ans=false;
struct node
{
int x, y;
};
int judge(int x, int y)
{
return x >= 0 && x < n&&y >= 0 && y < m;
}//判断是否出界
void dfs(int x,int y,int c)
{
if (flag)
return;
if (!judge(x, y))
return;
int record = abs(x- ex) + abs(y - ey);
record = t - record - c;//总的行走步数一定为偶数,注意奇偶剪枝的思想
if (record % 2 != 0)
{
return;
}//奇偶剪枝
if (map[x][y] == 'D'&&c == t)
{
flag = ans = true;
return;
}
node now;
for (int i = 0; i < 4; i++)
{
now.x = x + dir[i][0];
now.y = y + dir[i][1];
if (!visit[now.x][now.y] && map[now.x][now.y] != 'X')
{
visit[now.x][now.y] = 1;
dfs(now.x, now.y, c+1);
visit[now.x][now.y] = 0;//清除标记的操作
}
}
}
int main()
{
while (cin >> n >> m >> t)
{
if (n == 0 && m == 0 && t == 0)
break;
int k = 0;
memset(map, 0, sizeof(map));
memset(visit, 0, sizeof(visit));
flag = ans = false;
for (int i = 0; i < n; i++)
{
cin >> map[i];
for (int j = 0; j < m; j++)
{
if (map[i][j] == 'S')
{
sx = i;
sy = j;
visit[i][j] = 1;
}
if (map[i][j] == 'D')
{
ex = i;
ey = j;
}
if (map[i][j] == 'X')
k++;
}
}
if (n*m - k - 1 >= t)//判断可供行走的位置是否满足条件
dfs(sx, sy, 0);
if (ans)
printf("YES\n");
else
printf("NO\n");
}
getchar();
getchar();
return 0;
}
1、学到了奇偶剪枝的思想(以下内容为转载)
奇偶剪枝:
是数据结构的搜索中,剪枝的一种特殊小技巧。
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s | ||||
| | ||||
| | ||||
| | ||||
+ | — | — | — | e |
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
s | — | — | — | |
— | — | + | ||
| | + | |||
| | ||||
+ | — | — | — | e |
如图,为一般情况下非最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证);
故,若t-[abs(ex-sx)+abs(ey-sy)]结果为非偶数(奇数),则无法在t步恰好到达;
返回,false;
反之亦反。
2、我自己对于奇偶剪枝的理解,因为从起点到终点,行进的方向只能是上下左右四个方向,若满足这个条件,从起点到终点必定是偶数次行走,可以画个图理解一下,而此处的奇偶剪枝对于优化很有帮助,避免子节点的不必要的搜索,不满足奇偶条件则直接返回,节省运行时间
3、其余则是dfs与bfs模板化的思路,注意细节判断