双端队列BFSAcWing电路维修
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双端队列BFSAcWing电路维修相关的知识,希望对你有一定的参考价值。
- 博客主页: https://blog.csdn.net/qq_50285142
- 欢迎点赞👍收藏✨关注❤留言 📝 如有错误,敬请指正
- 🎈虽然生活很难,但我们也要一直走下去🎈
题目链接
思路:
使用双端队列解决边权值只有0和1的图的问题
如果某边的权值为1,则加入队尾
如果某边的权值为0,则加入队首,优先选择边权值为0的节点进行扩展
本题的思想类似于dijkstra算法,维护两个集合,一个是已经找到最小距离的集合,另一个是最小距离的点的扩展的集合。
双端队列中的点都是待扩展的点的集合,而出队的点就是找到最小距离的点的集合,故只要点一出队,那么这个点的最小距离就确定了。
四个坐标的解释:
s[] = "\\\\/\\\\/"
代表左上,右上,右下,左下四个方向的我们设置的默认路径,‘\\’为转义符,需要两个‘\\’才可以
dx[]={-1,-1,1,1},dy[]={-1,1,1,-1};
代表从当前点走到左上右上右下左下的四个方向的对角的点的坐标变化
ix[]={-1,-1,0,0},iy[]={-1,0,0,-1};
代表左上,右上,右下,左下四个方向的对应的方格的路径,默认每个方格的路径用该方格左上的角的点进行表示
默认每个点的距离为无穷大,先设置(0,0)点的距离为0,以(0,0)点进行扩展,不断寻找最短路径
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
const int N = 505,M = 505;
const int dx[]={-1,-1,1,1},dy[]={-1,1,1,-1};
const int ix[]={-1,-1,0,0},iy[]={-1,0,0,-1};
char g[N][M];
int n,m;
int dis[N][M];
bool st[N][M];
int bfs()
{
memset(dis,0x3f,sizeof dis);
memset(st,false,sizeof st);
char s[] = "\\\\/\\\\/";
deque<pii>q;
dis[0][0] = 0;
q.push_front({0,0});
while(!q.empty())
{
pii t = q.front();
q.pop_front();
if(st[t.fi][t.se]) continue;
st[t.fi][t.se] = true;
for(int i=0;i<4;i++)
{
int nx = t.fi + dx[i];
int ny = t.se + dy[i];
if(nx<0 or nx>n or ny<0 or ny>m) continue;
int xx = t.fi + ix[i],yy = t.se + iy[i];
int w = 0;
if(g[xx][yy]!=s[i]) w = 1;
if(dis[nx][ny] > dis[t.fi][t.se] + w)
{
dis[nx][ny] = dis[t.fi][t.se] + w;
if(w) q.push_back({nx,ny});
else q.push_front({nx,ny});
}
}
}
return dis[n][m];
}
void solve()
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>g[i];
int d = bfs();
if(d==0x3f3f3f3f) cout<<"NO SOLUTION\\n";
else cout<<d<<'\\n';
return ;
}
int main()
{
int _;
cin>>_;
while(_--)
{
solve();
}
return 0;
}
往期优质文章推荐
以上是关于双端队列BFSAcWing电路维修的主要内容,如果未能解决你的问题,请参考以下文章