标签:思考 适用于 mat return ... 双端队列 secret [] 了解
如果你不了解双端队列 deque
的话,请先去学习。
双端队列 BFS
又称 0-1 BFS
边权值为可能有,也可能没有(由于 BFS
适用于权值为 \(1\) 的图,所以一般是 \(0\) \(or\) \(1\)),或者能够转化为这种边权值的最短路问题。
例如在走迷宫问题中,你可以花 \(1\) 个金币走 \(5\) 步,也可以不花金币走 \(1\) 步,这就可以用 0-1 BFS
解决。
把没有权值的边扩展到的点放到队首,有权值的边扩展到的点放到队尾。
下面是伪代码:
while(队列不为空)
{
int u = 队首;
弹出队首;
for(枚举 u 的邻居)
{
更新数据
if(...)
添加到队首;
else
添加到队尾;
}
}
一个 \(n \times m\) 的图,现在有一束激光从左上角往右边射出,每遇到 ‘#‘,你可以选择光线往四个方向射出,或者什么都不做,问最少需要多少个 ‘#‘ 往四个方向射出才能使光线在第 \(n\) 行往右边射出。
此题目正解不是 0-1 BFS
但是适用 0-1 BFS
可以不需要思考过程,赛时许多大佬都是这么做的。
做法很简单,一个方向射出不需要花费(\(0\)),而往四个方向射出需要花费(\(1\)),然后直接来就可以了。
#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