浅谈双端队列广搜

Posted lyfoi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈双端队列广搜相关的知识,希望对你有一定的参考价值。

什么是双端队列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 imes 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;
}

以上是关于浅谈双端队列广搜的主要内容,如果未能解决你的问题,请参考以下文章

175. 电路维修双端队列广搜

[bfs] aw175. 电路维修(双端队列广搜+dijkstra理解+好题+难题)

浅谈双码流与三码流

第十一节 双端队列的概念和python代码实现

Python数据结构学习笔记——队列和双端队列

双端队列