1. 程式人生 > >淺談雙端隊列廣搜

淺談雙端隊列廣搜

添加 擴展 [] amp 多少 space [1] 彈出 c-c

什麽是雙端隊列BFS?

如果你不了解雙端隊列 deque 的話,請先去學習。

雙端隊列 BFS 又稱 0-1 BFS

適用範圍

邊權值為可能有,也可能沒有(由於 BFS 適用於權值為 \(1\) 的圖,所以一般是 \(0\) \(or\) \(1\)),或者能夠轉化為這種邊權值的最短路問題。

例如在走迷宮問題中,你可以花 \(1\) 個金幣走 \(5\) 步,也可以不花金幣走 \(1\) 步,這就可以用 0-1 BFS 解決。

實現

把沒有權值的邊擴展到的點放到隊首,有權值的邊擴展到的點放到隊尾。

下面是偽代碼:

while(隊列不為空) 
{
    int u = 隊首; 
    彈出隊首;
    for(枚舉 u 的鄰居) 
    {
        更新數據 
        if(...) 
          添加到隊首;
         else
          添加到隊尾;
    }
}

Croc Champ 2012 - Round 1 B Chamber of Secrets

翻譯

一個 \(n \times m\) 的圖,現在有一束激光從左上角往右邊射出,每遇到 ‘#‘,你可以選擇光線往四個方向射出,或者什麽都不做,問最少需要多少個 ‘#‘ 往四個方向射出才能使光線在第 \(n\) 行往右邊射出。

思路

此題目正解不是 0-1 BFS 但是適用 0-1 BFS 可以不需要思考過程,賽時許多大佬都是這麽做的。

做法很簡單,一個方向射出不需要花費(\(0\)),而往四個方向射出需要花費(\(1\)),然後直接來就可以了。

Code

#include<bits/stdc++.h>
using namespace std;
#define INF (1<<29)
int n,m;
char grid[1001][1001];
int dist[1001][1001][4];
int vis[1001][1001][4];
int fx[]={1,-1,0,0};
int fy[]={0,0,1,-1};
deque <int> q;
void add_front(int x,int y,int dir,int d)
{
    if(d<dist[x][y][dir])
    {
        dist[x][y][dir]=d;
        q.push_front(dir);
        q.push_front(y);
        q.push_front(x);
    }
}
void add_back(int x,int y,int dir,int d)
{
    if(d<dist[x][y][dir])
    {
        dist[x][y][dir]=d;
        q.push_back(x);
        q.push_back(y);
        q.push_back(dir);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        cin>>grid[i];

    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            for(int k=0;k<4;k++)
                dist[i][j][k]=INF;

    add_front(n-1,m-1,3,0);

    while(!q.empty())
    {
        int x=q[0],y=q[1],dir=q[2];
        q.pop_front();
        q.pop_front();
        q.pop_front();
        if(vis[x][y][dir])
            continue;
        vis[x][y][dir]=true;
        int d=dist[x][y][dir];
        int nx=x+fx[dir],ny=y+fy[dir];
        if(nx>=0&&nx<n&&ny>=0&&ny<m)
            add_front(nx,ny,dir,d);
        if(grid[x][y]=='#')
            for(int i=0;i<4;i++)
                if(i!=dir)
                    add_back(x,y,i,d+1);
    }
    if(dist[0][0][3]==INF)
        cout<<-1<<endl;
    else
        cout<<dist[0][0][3]<<endl;
    return 0;
}

淺談雙端隊列廣搜