题目:http://acm.hdu.edu.cn/showproblem.php?pid=1728
题意:'.'可以走,'*'障碍,给你起点终点,问从起点最多拐k次弯,问能不能到终点。。
开始做的时候,以为,用优先队列拐弯数小的优先,然后每次用队头遍历旁边的4个点。。。。结果WA了。。。而且还用东西来处理是否拐弯。。。
用BFS来处理最优解问题要用队头来遍历完所有最优解并且进队,再重复。。。而上面WA的原因是,我只把相邻的4个点进了队,而在同行,同列还有最优解没进队,导致那些之前没进队的,进队的时候就已经不是最优解了。。。。
这题要用队头遍历4个方向(而不是4个点)。。。每步都是最优,所以最后也是最优。。。。
vis[][]是该点有没遍历过,遍历过的就已经最优了。。。即,队列里的都已经最优了,也就是队头也是最优的。。。。
要特别注意代码标成//********的地方
对比正确和错误代码的图:
错误代码是while(里有!vis[][])而下面没有vis[][];
但是,如果左边那竖的二变成三的时候,那3个'.'就每人遍历了,所以代码是队头遍历同行同列中不出界且!='*'的
点,跳过标记过的(已经最优了),将未标记的点入队。。。
还有我的q1.turn_num = -1初始化为-1(为了把起点同行同列拐弯数是0,所以如果题目起点等于终点的话,最少拐弯数就成了-1)。。。。其实如果题目改成求最少拐弯数的话,就稍微判断一下是不是起点等于终点。。。。
代码:
#include <iostream> #include <queue> using namespace std; const int M = 111; int n, m; int max_turn; int star_x, star_y, end_x, end_y; char g[M][M]; bool vis[M][M]; int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; //右,下,左,上 struct Node { int x, y; int turn_num; }; int Bfs() { queue <Node> q; Node q1; q1.x = star_x; q1.y = star_y; q1.turn_num = -1; q.push(q1); vis[star_x][star_y] = 1; while (!q.empty()) { Node q2 = q.front(); q.pop(); if (q2.x == end_x && q2.y == end_y && q2.turn_num <= max_turn) { return 1; } q1.turn_num = q2.turn_num + 1; for (int i = 0; i < 4; i++) { q1.x = q2.x + dir[i][0]; q1.y = q2.y + dir[i][1]; while (q1.x >= 1 && q1.x <= n && q1.y >= 1 && q1.y <= m && g[q1.x][q1.y] == '.'/* && !vis[q1.x][q1.y]*/)//********** { if (!vis[q1.x][q1.y])//********************************* { q.push(q1); vis[q1.x][q1.y] = 1; } q1.x += dir[i][0]; q1.y += dir[i][1]; } } } return 0; } int main() { int t; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { scanf(" %c", &g[i][j]); } } scanf("%d%d%d%d%d", &max_turn, &star_y, &star_x, &end_y, &end_x); memset(vis, 0, sizeof(vis)); if (Bfs()) { puts("yes"); } else { puts("no"); } } return 0; }