标签:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 typedef struct Node 6 { 7 int x, y; 8 }Node; 9 10 const int MAX = 10000; 11 const int N = 110; 12 const int dir[4][2] = { {-1,0}, {0,1}, {1,0}, {0,-1} };//移动方向 13 bool visit[N][N]; //标记数组 14 char board[N][N]; //棋盘 15 int turn[N][N]; //turn数组用于记录棋盘上各点已知的最少的转弯次数 16 Node origin, destination;//起点、终点 17 int maxTurnCount; //路痴所能承受的最大转弯次数 18 int m, n; //棋盘的行、列 19 20 21 inline bool inBoard(const int &row, const int &col) 22 { 23 return 0 <= row && row < m && 0 <= col && col < n; 24 } 25 26 /* dfs搜索(参数含义:行、列、上一次移动的方向) */ 27 bool dfs(const int &row, const int &col, int direction) 28 { 29 //在路痴可以承受的转向次数内到达终点 30 if (row == destination.x && col == destination.y && turn[row][col] <= maxTurnCount) 31 return true; 32 33 //转向的次数超过路痴所能承受的次数,路痴已经晕了,因此不可取 34 if (turn[row][col] > maxTurnCount) 35 return false; 36 37 //路痴的位置与终点不在同一行同一列,那么至少需要再转向一次,但是当前的转向次数已经等于路痴所能承受的最大转弯次数 38 if (row != destination.x && col != destination.y && turn[row][col] == maxTurnCount) 39 return false; 40 41 for (int i = 0; i < 4; ++i) 42 { 43 int r = row + dir[i][0]; 44 int c = col + dir[i][1]; 45 if (true == inBoard(r, c) && ‘.‘ == board[r][c] && false == visit[r][c]) 46 { 47 /* turn[r][c]记录的是历史上走到(r,c)所用的最短的转弯次数,turn[r][c]的初始值MAX */ 48 /* 剪枝1:从(row, col)位置走向(r, c)位置,如果turn[r][c] < turn[row][col],说明之前 49 路痴已经走到过这里了,并且上次的转弯次数比这次小,上次都没走到终点,这次更加走不到。 50 相等的情况不能剪掉,举个栗子:从起点(1, 1),走向终点(3, 5),一种方法是向右走,一种方法 51 是向下走。向右走的时候,走到(3, 4)的时候,转弯次数是1,那么turn[3][4] = 1,在转一次 52 才走到,那么需要转两次;向下走的时候,又走到(3, 4),转弯次数也是1,由于之前走到过, 53 然而两次转弯次数相同,后一种情况(走到终点只需要转弯一次)被剪枝剪掉了,如果题目给 54 出的最大转弯次数是1,那么就得不到正确答案了。 55 ....* 56 .**.* 57 ..... 58 */ 59 if (turn[r][c] < turn[row][col]) 60 continue; 61 62 /* 剪枝2:跟剪枝1的原理类似,从(row, col)走向(r, c),由于方向改变了,因此转弯次数 63 需要加一,转弯次数加一后如果比(r, c)历史上的转弯次数还多,就需要把这种情况给剪掉。 64 相等的情况不能剪掉 */ 65 if (-1 != direction && i != direction && turn[r][c] < turn[row][col] + 1) 66 continue; 67 68 if (-1 != direction && i != direction) 69 turn[r][c] = turn[row][col] + 1;//移动方向与之前的不同,转弯次数+1 70 else 71 turn[r][c] = turn[row][col]; //移动方向与之前的相同,转弯次数不变 72 73 visit[r][c] = true; 74 75 if (true == dfs(r, c, i)) return true; 76 77 //回溯 78 visit[r][c] = false; 79 } 80 } 81 return false; 82 } 83 84 void input(void) 85 { 86 scanf("%d %d", &m, &n); //输入行、列 87 for (int i = 0; i < m; ++i) //输入棋盘 88 scanf("%s", board[i]); 89 90 //这里有坑:“5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m)” 91 //1 ≤ x1, x2 ≤ n => x1,x2是列;1 ≤ y1, y2 ≤ m => y1,y2是行 92 //出题人挖的坑,不要被惯性思维束缚了 93 scanf("%d %d %d %d %d", &maxTurnCount, &origin.y, &origin.x, &destination.y, &destination.x); 94 95 //初始化数据 96 for (int i = 0; i < m; ++i) 97 for (int j = 0; j < n; ++j) 98 turn[i][j] = MAX; 99 memset(visit, 0, sizeof(visit)); 100 origin.y--; //题目给出的坐标从1开始,因此需要对坐标进行处理,让其从0开始 101 origin.x--; 102 destination.y--; 103 destination.x--; 104 } 105 106 int main(void) 107 { 108 int t;//测试组数 109 scanf("%d", &t); 110 for (int k = 0; k < t; ++k) 111 { 112 input(); 113 visit[origin.x][origin.y] = true; 114 turn[origin.x][origin.y] = 0; 115 if (true == dfs(origin.x, origin.y, -1)) 116 printf("yes\n"); 117 else 118 printf("no\n"); 119 } 120 return 0; 121 }
标签:
原文地址:http://www.cnblogs.com/yongqiang/p/5693077.html