Ignatius and the Princess I HDU - 1026 BFS+優先隊列+記錄路徑

求迷宮最短路徑長度和路徑。由於有些點會停留打怪,需要多增加停留的時間,而不只是加1。由於隊列中每一個擴展點的權重不一樣,所以不能按平常的BFS解題。這裏採用優先隊列,權重大也就是耗時耗路徑少的點優先出隊。題目還有一個難點就是最短路徑。由於BFS就是查找最短路徑,所以出列的點構成的路徑就是最短路徑,我們可以從終點開始往起點搜索,記錄擴展點的後繼,最後在從起點擴展後繼遍歷輸出到終點。

這裏使用功能C++STL的優先隊列 priority_queue

優先隊列容器與隊列一樣,只能從隊尾插入元素,從隊首刪除元素。但是它有一個特性,就是隊列中最大的元素總是位於隊首,所以出隊時,並非按照先進先出的原則進行,而是將當前隊列中最大的元素出隊。這點類似於給隊列裏的元素進行了由大到小的順序排序。元素的比較規則默認按元素值由大到小排序,可以重載“<”操作符來重新定義比較規則。

優先級隊列可以用向量(vector)或雙向隊列(deque)來實現(注意list container不能用來實現queue,因爲list的迭代器不是任意存取iterator,而pop中用到堆排序時是要求randomaccess iterator 的!):
priority_queue<vector<int>, less<int> > pq1;     // 使用遞增less<int>函數對象排序
priority_queue<deque<int>, greater<int> > pq2;   // 使用遞減greater<int>函數對象排序
其成員函數有“判空(empty)” 、“尺寸(Size)” 、“棧頂元素(top)” 、“壓棧(push)” 、“彈棧(pop)”等。
在這裏插入圖片描述

#include <queue>
#include <iostream>
#include <cstring>
#include <cstdio>
#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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章