【题意】:输入三个数N、M、T,分别代表行列时间。迷宫中S代表初始位置,D代表门,'.'代表可以走的路。小狗一秒只移动一格。有解输出YES,没有NO。至关重要的条件: on exactly ,表示正好在T秒时间到达,并且这也是奇偶剪枝的关键。不剪枝的话超时TLE。
【奇偶剪枝】:内容来自百度百科。
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
如图,为一般情况下非最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证)。
结论:
推广之,若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;
返回,false;
反之亦反。
【AC代码】:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define MAX 7+1
int N = 0, M = 0, T = 0;
int cnt = -1, res = 0;
int sx = 0, sy = 0, ex = 0, ey = 0;
int stepx[] = {-1,0,1,0}, stepy[] = {0,1,0,-1};
int visited[MAX][MAX];
char maze[MAX][MAX];
void dfs(int x, int y);
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int i = 0, j = 0;
while (cin >> N >> M >> T && N && M && T)
{
//initial
cnt=-1, res = 0;
memset(visited, 0, sizeof(visited));
//input
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
{
cin >> maze[i][j];
if ('S' == maze[i][j])
{
sx = i, sy = j;
}
else if ('D' == maze[i][j])
{
ex = i, ey = j;
}
else if ('X' == maze[i][j])
{
visited[i][j] = 1;
}
}
}
//search
dfs(sx, sy);
if (res)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
void dfs(int x, int y)
{
int i = 0;
if (x<0 || x>=N || y<0 || y>=M)
return;
visited[x][y] = 1;
cnt++;
if ('D'==maze[x][y] && cnt == T)
{
res = 1;
return;
}
int temp = T-abs(ex-sx)-abs(ey-sy);
if (temp<0 || temp&1)
return;
for (i = 0; i < 4; i++)
{
if (0 == visited[x+stepx[i]][y+stepy[i]] && !res)
{
dfs(x+stepx[i], y+stepy[i]);
}
}
cnt--;
visited[x][y] = 0;
}
其他:1. 位运算判断奇偶的方法。temp&1。