码迷,mamicode.com
首页 > 其他好文 > 详细

浅谈双端队列广搜

时间:2018-09-09 11:41:19      阅读:903      评论:0      收藏:0      [点我收藏+]

标签:思考   适用于   mat   return   ...   双端队列   secret   []   了解   

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

浅谈双端队列广搜

标签:思考   适用于   mat   return   ...   双端队列   secret   []   了解   

原文地址:https://www.cnblogs.com/lyfoi/p/9612428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!