参考了两个灰常详细的博客,把奇偶剪枝讲得很清楚,致谢致谢!链接如下
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#define N 10
using namespace std;
int n, m, t;
bool vis[N][N];
char g[N][N];
bool escape = false;
int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
int stx, sty, dorx, dory;
void dfs(int x, int y, int d) // 分别代表坐标和已走步数(距离distance)
{
if(x == dorx && y == dory && d == t) // 如果到达D时,门刚刚打开
{
escape = true;
return;
}
int judge = t - d - (abs(dorx - x) + abs(dory - y)); // 判断在这种状态下还有没有可能到达终点
// judge的值等于剩余步数 - 最短路径(比较粗略,不考虑墙)
if(judge < 0 || judge & 1) return; // 如果judge剩余步数不足或者与最短路径的奇偶性不同,剪枝
for(int i = 0; i < n; i ++)
{
int xx = x + dx[i], yy = y + dy[i];
if(xx >= 0 && xx < n && yy >= 0 && yy < m && !vis[xx][yy] && (g[xx][yy] == '.' || g[xx][yy] == 'D'))
{
vis[xx][yy] = true;
dfs(xx, yy, d + 1);
if(escape) return; // 如果已经找到了解,返回
vis[xx][yy] = false;
}
}
return;
}
int main()
{
while(scanf("%d%d%d", &n, &m, &t) && (n || m || t))
{
escape = false;
int walls = 0; // 记录有多少个墙
memset(vis, 0, sizeof vis);
cin.get();
for (int i = 0; i < n; i ++, cin.get())
{
for(int j = 0; j < m; j ++)
{
char ch;
scanf("%c", &ch);
g[i][j] = ch;
if(ch == 'X')
{
walls ++;
}
else if(ch == 'D')
{
dorx = i, dory = j;
}
else if(ch == 'S')
{
stx = i, sty = j;
}
}
}
if(n * m - walls <= t) // 如果总的可走步数都不够的话,直接返回NO
{
puts("NO");
continue;
}
vis[stx][sty] = true;
dfs(stx, sty, 0);
if(escape)
puts("YES");
else puts("NO");
}
return 0;
}