传送门UVa 10047 - The Monocycle
走迷宫的一道题,和以往不同的是这次走过的地方可以走,除非状态(颜色,方向)和上一次完全相同。
所以要开一个四维数组,记录这两个状态。
题目要求用时最短,这时就需要一个优先队列。每次从队列中取元素时,总是取的用时最短的那个。所以最后满足终点条件的时候输出的就是时间最短的。
因为优先队列默认从大到小排序,所以要重载<运算符(我是这么理解的),不过应该也可以写一个比较函数,改变默认排序顺序。
还是参考了@shuangde800的解题报告,加了点注释,方便大家理解。
至此,除了最后一题,图专题结束。最后一题就等暑假结束再来吧。。。
#include <cstdio> #include <cstring> #include <queue> #include <cmath> using namespace std; struct Node { int dir, color, time; int x, y; friend bool operator < (const Node &a, const Node &b) { return a.time > b.time; } }; const int MAXN = 30; char maze[MAXN][MAXN]; int vis[MAXN][MAXN][4][5]; // 绿0,白1,黑2,红3,蓝4 int dir[][2] = {{-1,0},{0,1},{1,0},{0,-1}}; // 上0,右1,下2,左3,这里要和i对应,不然会错。 int xStart, yStart, xTarget, yTarget; //起点和终点的坐标 int row, colomn; Node start, temp, stemp; priority_queue<Node> que; void BFS(); int main() { //freopen("input.txt", "r", stdin); int i, j, n; bool sFind, tFind; int cnt = 1; while (scanf("%d%d%*c", &row, &colomn)) { memset(vis, 0, sizeof(vis)); memset(maze, 0, sizeof(maze)); sFind = tFind = false; if (row + colomn == 0) break; for (i = 0; i < row; i++) scanf("%s%*c", maze[i]); for (i = 0; i < row; i++) { for (j = 0; j < strlen(maze[i]); j++) { if (sFind && tFind) //如果起始坐标和终点坐标都找到,退出。 break; if (maze[i][j] == 'S') { xStart = i, yStart = j; sFind = true; } if (maze[i][j] == 'T') { xTarget = i, yTarget = j; tFind = true; } } } start.x = xStart, start.y = yStart, start.color = start.dir = start.time = 0; if (cnt != 1) printf("\n"); printf("Case #%d\n", cnt++); BFS(); } return 0; } void BFS() { while (!que.empty()) //清空队列。 que.pop(); vis[start.x][start.y][start.dir][start.color] = 1; que.push(start); while (!que.empty()) { temp = que.top(); que.pop(); for (int i = 0; i < 4; i++) //按顺序分别对应。上0,右1,下2,左3 { int dx = temp.x + dir[i][0]; int dy = temp.y + dir[i][1]; if (dx >= 0 && dy >= 0 && dx < row && dy < colomn && maze[dx][dy] != '#') { if (temp.dir == i) //如果要走的方向和当前方向相同,直接走,变颜色,不变方向。 { stemp.time = temp.time + 1; stemp.color = (temp.color + 1) % 5; stemp.dir = i; stemp.x = dx, stemp.y = dy; } else //如果方向和车头不一致,原地转弯 { if (abs(temp.dir - i) == 2) //相差180°,时间+2,坐标都不变 stemp.time = temp.time + 2; else stemp.time = temp.time + 1; stemp.dir = i; stemp.color = temp.color; stemp.x = temp.x, stemp.y = temp.y; } if (!vis[stemp.x][stemp.y][i][stemp.color]) { if (stemp.x == xTarget && stemp.y == yTarget && stemp.color == 0) { printf("minimum time = %d sec\n", stemp.time); return; } que.push(stemp); vis[stemp.x][stemp.y][i][stemp.color] = 1; } } } } printf("destination not reachable\n"); }