题目链接: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"; } }