题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010
一. 题意:
小狗从S出发,1s跳一个格子,Ts后恰好跳到D,不可以跳跳过的格子。问是否跳得出去。
二. 易错点:
我要先发图!
1. 要记得剪枝。
2. 在判断是否到达门的时候,最好用坐标,因为用maze[i][j] == 'D'的话。
首先你要记得判断后再把它置为 ‘X’
其次也是致命的,如果门那里回溯过一次的话,你会把它变为 ‘.’ ,这样的话下次再找到那里就失效了,有人会说设一个标志,当时你判断是否进去怎么办?就是这个找出来的我就AC了哈哈哈哈哈哈哈!虽然600多ms险过。
三. 知识预备
1. 奇偶剪枝:
从S到D,最短路径minPath = abs(iStart - iEnd) + abs(iStart + iEnd)
如果要绕道的话,绕过的道一定为偶数,因为要出去再返回到原道路上。
因此可以用总时间T减去最短路径,那么就可以得到偏离的道路,如果不是偶数直接剪枝。
而且把剪枝放在外面,因为放在DFS里面完全没有意义,想一下走一下你的时间就减少1s。然后你再用剩下的时间去判断有什么意义,不是跟走之前判断一个结果吗。只是徒增你的栈空间。
2. 位运算判断奇偶性
纯属装X技巧:计算机用二进制表示整型数。跟1进行&运算,如果最后一位是1,说明是奇数,计算后结果为1。如果最后一位是0,说明是偶数。计算后结果为0。听说位运算速度快哦!(虽然也听说微观优化你绝对比不过编译器)
四. 贴代码啦啦啦
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
char maze[8][8];
int N, M, T, iStart, jStart, iEnd, jEnd, cou;
bool check(int i, int j)
{
if(i < 0 || i >= N || j < 0 ||
j >= M ||'X' == maze[i][j])
return false;
else
return true;
}
int movei[4] = {-1, 0, 1, 0};
int movej[4] = {0, -1, 0, 1};
bool dfs(int i, int j)
{
int minPath = abs(iEnd - i) + abs(jEnd - j);
if(T - cou < minPath)
return false;
if(i == iEnd && j == jEnd && cou == T){ //Attention: You can't use "maze[i][j] == 'D' here
return true;
}
maze[i][j] = 'X';
int m;
for(m = 0; m < 4; m++){
if(check(i + movei[m], j + movej[m])){
cou++;
if(dfs(i + movei[m], j + movej[m]))
return true;
cou--;
maze[i + movei[m]][j + movej[m]] = '.';
}
}
return false;
}
int main()
{
//freopen("in.txt", "r", stdin);
int i, j;
while(1){
cin>>N>>M>>T;
cou = 0;
if(!N && !M && !T)
break;
for(i = 0; i < N; i++)
cin>>maze[i];
for(i = 0; i < N; i++)
for(j = 0; j < M; j++){
if('S' == maze[i][j]){
iStart = i;
jStart = j;
}
if('D' == maze[i][j]){
iEnd = i;
jEnd = j;
}
}
int minPath = abs(iStart - iEnd) + abs(jStart - jEnd);
if((T - minPath) & 1){
cout<<"NO\n";
}
else if(dfs(iStart, jStart))
cout<<"YES\n";
else
cout<<"NO\n";
}
}