迷宮【科大訊飛杯K題】【BFS+單調隊列/單調棧】

鏈接:https://ac.nowcoder.com/acm/contest/5278/K
來源:牛客網
 

題目描述

SuperSodaSea 在玩一個走迷宮的遊戲。迷宮是一個大小爲 n×m的矩陣,從上到下依次給行編號爲 0,1,…n−1,從左到右依次給列編號爲 0,1,…,m−1。
遊戲規則很簡單:從起點出發,每步操作可以移動到上、下、左、右四個方向的空地上,直到終點。
爲了增加遊戲的難度,在這個遊戲中,從起點到終點並不一定會有直接的通路。當然,相對應地,玩家可以使用名爲“穿越”的技能:從一塊空地移動到距離至多爲 d 另一片空地上(起點和終點也視爲空地),無論中間是否有障礙。
在使用技能時的距離是指“切比雪夫距離”,即如果從 (x1​,y1​)穿越到(x2​,y2​)需要滿足 max⁡{∣x1−x2∣,∣y1−y2∣}≤d。“穿越”只能最多使用一次,使用時算一步操作。
現在你需要幫 SuperSodaSea 計算出給定的迷宮,他最少需要多少步才能到達終點,並給出一個方案。

輸入描述:

第一行包含 3 個整數 n, m, d (1≤n,m≤2 0001≤n,m≤2000, 0≤d≤2 0000≤d≤2000),中間以空格分隔,分別表示地圖的行數、列數和穿越的最大距離。
接下來 n 行,每行包含一個長度爲 m 的字符串,表示地圖。
其中,. 表示空地,X 表示障礙,S 表示起點,T表示終點。
輸入保證有且僅有一個起點和一個終點。

輸出描述:

第一行輸出一個整數 t 表示最少所需要的步驟。
接下來 t + 1 行,每行輸出兩個整數 xi,yixi​,yi​,中間以空格分隔, 表示每一步所經過的座標。其中,第一行和最後一行應分別對應起點和終點。
特別地,如果沒有可以走到終點的方案,則在一行輸出 -1。
答案不唯一,任何符合要求的答案都會被判爲正確。

  首先,先想一下暴力的其中之一個解法,我們可以枚舉使用“穿越”的那條邊的起點和終點。所以我們可以bfs從起點S跑,和終點T跑,然後取枚舉的最小值,然後輸出答案就是了。

  上述做法的時間複雜度爲O(N * M * D^2)

  但是,我們可以想辦法去把這個O(D^2)給優化掉,這裏就要引入單調棧和單調隊列了。

  我們想知道這個點出去的2D * 2D的面積塊的最小值(從T到點的最短距離),儘管可以用四叉樹等數據結構來O(log(N))的維護這個信息,但是能多優化就多優化一下。

  我們可以跑一個單調遞增的單調隊列/棧,先從左往右跑,再從右往左,如此,就可以確定每一行的在範圍-D \sim +D這個範圍的最值了,用一個二維數組進行存儲,然後就是我們對現在這個存儲的一維信息再從上到下和從下到上的再來跑兩次這樣的單調隊列/棧,我們就可以確定每個點的在範圍2D * 2D的“穿越”能到的最小值了。

  然後就是各種維護了,代碼較長,慎讀。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define Big_INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e3 + 7;
const int dir[4][2] =
{
    -1, 0,
    0, -1,
    0, 1,
    1, 0
};
int N, M, D, sx, sy, ex, ey, nx, ny, tx, ty;
inline bool In_Map(int x, int y) { return x >= 0 && y >= 0 && x < N && y < M; }
char mp[maxN][maxN];
bool vis[maxN][maxN][2];
int dis[maxN][maxN][2];
struct node
{
    int x, y, t;
    node(int a=0, int b=0, int c=0):x(a), y(b), t(c) {}
    friend bool operator < (node e1, node e2) { return e1.t > e2.t; }
} now;
struct Recoder
{
    short int x, y;
    Recoder(short int a=0, short int b=0):x(a), y(b) {}
} las[maxN][maxN], Ans[maxN * maxN];
int Stop = 0;
queue<node> Q;
void bfs(int x, int y, int op)
{
    dis[x][y][op] = 0;
    vis[x][y][op] = true;
    Q.push(node(x, y, 0));
    while(!Q.empty())
    {
        now = Q.front(); Q.pop();
        x = now.x; y = now.y;
        for(int i=0, xx, yy; i<4; i++)
        {
            xx = x + dir[i][0]; yy = y + dir[i][1];
            if(!In_Map(xx, yy) || mp[xx][yy] == 'X' || vis[xx][yy][op]) continue;
            vis[xx][yy][op] = true; dis[xx][yy][op] = now.t + 1;
            if(!op) las[xx][yy] = Recoder(x, y);
            Q.push(node(xx, yy, dis[xx][yy][op]));
        }
    }
}
struct Que_Node
{
    short int x, y; int val;
    Que_Node(short int a=0, short int b=0, int c=0):x(a), y(b), val(c) {}
    friend bool operator < (Que_Node e1, Que_Node e2) { return e1.val < e2.val; }
} que[maxN], h[maxN][maxN], s[maxN][maxN];
int top, tail;
int main()
{
    scanf("%d%d%d", &N, &M, &D);
    for(int i=0; i<N; i++) scanf("%s", mp[i]);
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<M; j++)
        {
            vis[i][j][0] = vis[i][j][1] = false; dis[i][j][0] = dis[i][j][1] = INF;
            if(mp[i][j] == 'S') { sx = i; sy = j; }
            if(mp[i][j] == 'T') { ex = i; ey = j; }
        }
    }
    bfs(sx, sy, 0);
    bfs(ex, ey, 1);
    int ans = INF;
    for(int i=0; i<N; i++)
    {
        top = tail = 0;
        for(int j=0; j<M; j++)
        {
            while(top < tail && que[top].y + D < j) top++;
            while(top < tail && que[tail - 1].val >= dis[i][j][1]) tail--;
            que[tail++] = Que_Node(i, j, dis[i][j][1]);
            h[i][j] = que[top];
        }
    }
    for(int i=0; i<N; i++)
    {
        top = tail = 0;
        for(int j=M - 1; j>=0; j--)
        {
            while(top < tail && que[top].y - D > j) top++;
            while(top < tail && que[tail - 1].val >= dis[i][j][1]) tail--;
            que[tail++] = Que_Node(i, j, dis[i][j][1]);
            if(h[i][j].val > que[top].val) h[i][j] = que[top];
        }
    }
    for(int j=0; j<M; j++)
    {
        top = tail = 0;
        for(int i=0; i<N; i++)
        {
            while(top < tail && que[top].x + D < i) top++;
            while(top < tail && que[tail - 1].val >= h[i][j].val) tail--;
            que[tail++] = h[i][j];
            s[i][j] = que[top];
        }
    }
    for(int j=0; j<M; j++)
    {
        top = tail = 0;
        for(int i=N-1; i>=0; i--)
        {
            while(top < tail && que[top].x - D > i) top++;
            while(top < tail && que[tail - 1].val >= h[i][j].val) tail--;
            que[tail++] = h[i][j];
            if(s[i][j].val > que[top].val) s[i][j] = que[top];
        }
    }
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<M; j++)
        {
            if(ans > dis[i][j][0] + s[i][j].val + 1)
            {
                nx = i; ny = j;
                tx = s[i][j].x; ty = s[i][j].y;
                ans = dis[i][j][0] + s[i][j].val + 1;
            }
        }
    }
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<M; j++)
        {
            if(ans > dis[i][j][0] + dis[i][j][1])
            {
                ans = dis[i][j][0] + dis[i][j][1];
                nx = tx = ex; ny = ty = ey;
            }
        }
    }
    if(ans == INF) printf("-1\n");
    else
    {
        printf("%d\n", ans);
        short int xx, yy, cop_x = nx, cop_y = ny;
        Ans[++Stop] = Recoder(nx, ny);
        while(!(nx == sx && ny == sy))
        {
            xx = las[nx][ny].x; yy = las[nx][ny].y;
            Ans[++Stop] = Recoder(xx, yy);
            nx = xx; ny = yy;
        }
        while(Stop)
        {
            printf("%d %d\n", Ans[Stop].x, Ans[Stop].y);
            Stop--;
        }
        for(int i=0; i<N; i++) for(int j=0; j<M; j++) vis[i][j][0] = false;
        bfs(tx, ty, 0);
        if(!(ex == cop_x && ey == cop_y)) Ans[++Stop] = Recoder(ex, ey);
        while(!(ex == tx && ey == ty))
        {
            xx = las[ex][ey].x; yy = las[ex][ey].y;
            Ans[++Stop] = Recoder(xx, yy);
            ex = xx; ey = yy;
        }
        while(Stop)
        {
            printf("%d %d\n", Ans[Stop].x, Ans[Stop].y);
            Stop--;
        }
    }
    return 0;
}

 

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