求迷宫最短路径长度和路径。由于有些点会停留打怪,需要多增加停留的时间,而不只是加1。由于队列中每一个扩展点的权重不一样,所以不能按平常的BFS解题。这里采用优先队列,权重大也就是耗时耗路径少的点优先出队。题目还有一个难点就是最短路径。由于BFS就是查找最短路径,所以出列的点构成的路径就是最短路径,我们可以从终点开始往起点搜索,记录扩展点的后继,最后在从起点扩展后继遍历输出到终点。
这里使用功能C++STL的优先队列 priority_queue
优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。这点类似于给队列里的元素进行了由大到小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。
优先级队列可以用向量(vector)或双向队列(deque)来实现(注意list container不能用来实现queue,因为list的迭代器不是任意存取iterator,而pop中用到堆排序时是要求randomaccess iterator 的!):
priority_queue
priority_queue
其成员函数有“判空(empty)” 、“尺寸(Size)” 、“栈顶元素(top)” 、“压栈(push)” 、“弹栈(pop)”等。
#include
#include
#include
#include
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int MAXN = 105;
char maze[MAXN][MAXN];//迷宫
int vis[MAXN][MAXN];//判断访问数组,1为已经访问,0为未访问
int n, m;//行、列
int dx[] = {1, 0, -1, 0};//方向矢量
int dy[] = {0, -1, 0, 1};
struct Point
{
int x, y, time;//坐标和花费的时间
bool operator < (const Point& a) const
{
return time > a.time;
}
};
struct nextnode
{
int x, y;
}Next[MAXN][MAXN];//后继数组
bool bfs(int x, int y)
{
vis[x][y] = 1;
Next[x][y].x = -1;//终点无后继
priority_queue<Point> q;
Point cur, tmp;
cur.x = x; cur.y = y; cur.time = 0;
if (isdigit(maze[x][y])) cur.time += maze[x][y] - '0';//终点可以有野怪,如果是数字字符,打怪停留
q.push(cur);
while (!q.empty())
{
cur = q.top();
q.pop();
if (cur.x == 0 && cur.y == 0)//到达起点
{
int sx = cur.x, sy = cur.y;
int t = 1;
printf("It takes %d seconds to reach the target position, let me show you the way.\n", cur.time);
while (Next[sx][sy].x != -1)
{
int nx = Next[sx][sy].x, ny = Next[sx][sy].y;
printf("%ds:(%d,%d)->(%d,%d)\n", t++, sx, sy, nx, ny);
if (isdigit(maze[nx][ny]))
_for (i, 0, maze[nx][ny] - '0')
printf("%ds:FIGHT AT (%d,%d)\n", t++, nx, ny);
sx = nx;
sy = ny;
}
return true;
}
_for (i, 0, 4)
{
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny] || maze[nx][ny] == 'X') continue;
vis[nx][ny] = 1;
tmp.x = nx; tmp.y = ny; tmp.time = cur.time + 1;
if (isdigit(maze[nx][ny])) tmp.time += maze[nx][ny] - '0';
//tmp的后继为cur点,不能设置前驱数组,因为cur的前驱有多个(多个扩展点在队列中)
Next[nx][ny].x = cur.x;
Next[nx][ny].y = cur.y;
q.push(tmp);
}
}
return false;
}
int main()
{
while (cin >> n >> m)
{
memset(vis, 0, sizeof(vis));
_for (i, 0, n) _for (j, 0, m) cin >> maze[i][j];
if (!bfs(n - 1, m - 1)) cout << "God please help our poor hero.\n";
cout << "FINISH\n";
}
return 0;
}