思路:dfs + 剪枝优化
要点1:当剩余可走步数<曼哈顿距离时一定无解
要点2:当T - f(曼哈顿距离)为奇数时,一定无解,因为一个点到终点的所有路径走的距离的奇偶性一定是一样的!绕路只能增加偶数的距离值,T - f可以简单的判断奇偶,优化算法
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <string.h> using namespace std; char mp[8][8];//小狗的迷宫地图! bool vis[8][8];//小狗的记忆,判断地板有没有走过 int n, m, t; bool flag;//记录是否有解 int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};//四个方向 #define check(xx,yy) (xx >= 0 && xx < n && yy >= 0 && yy < m)//判断小狗是否在迷宫中 int f(int x1,int y1,int x2,int y2){//曼哈顿距离(一点到另一点的最短距离) return abs(x1 - x2) + abs(y1 - y2); } int sx, sy, dx, dy; void dfs(int x,int y,int step){//step表示已经走了多少步 if(flag){ return;//如果找到答案,一步步退出dfs } int tmp = t - step - f(x, y, dx, dy); //t - step表示剩余能走几步,如果剩余距离小于曼哈顿距离,小狗一定走不出去,所以剪枝 if(tmp < 0){ return; } if(mp[x][y] == 'D'){//走到出口了,无论正确与否都要返回 if(step == t){ flag = 1;//找到答案 } return; } for (int i = 0; i < 4; i++){//向四个方向dfs int xx = x + dir[i][0]; int yy = y + dir[i][1]; if(check(xx,yy) && mp[xx][yy] != 'X' && !vis[xx][yy]){//如果这个方向是空路!而且没走过! vis[xx][yy] = 1;//标记已经走过了 dfs(xx, yy, step + 1);//找到所有路径 vis[xx][yy] = 0;//回溯 } } return; } int main(){ while(~scanf("%d%d%d",&n,&m,&t)){ if(n == 0 && m == 0 && t == 0){ break; } flag = 0; for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++){ cin >> mp[i][j]; if(mp[i][j] == 'S'){//标记起点 sx = i; sy = j; } if(mp[i][j] == 'D'){//标记终点 dx = i; dy = j; } } } memset(vis, 0, sizeof(vis)); vis[sx][sy] = 1;//标记起点已经走过 int tmp = t - f(sx, sy, dx, dy); if(tmp % 2 != 0){//如果tmp为奇数一定无解 puts("NO"); continue; } dfs(sx,sy,0);//搜索所有情况 if(flag){ puts("YES"); } else{ puts("NO"); } } return 0; }