浅谈双端队列广搜
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;
}
以上是关于浅谈双端队列广搜的主要内容,如果未能解决你的问题,请参考以下文章