2601 电路维修 (双端队列bfs\优先队列bfs(最短路))
描述
Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上。Rika的家里有一辆飞行车。有一天飞行车的电路板突然出现了故障,导致无法启动。
电路板的整体结构是一个R行C列的网格(R,C≤500),如右图所示。每个格点都是电线的接点,每个格子都包含一个电子元件。电子元件的主要部分是一个可旋转的、连接一条对角线上的两个接点的短电缆。在旋转之后,它就可以连接另一条对角线的两个接点。电路板左上角的接点接入直流电源,右下角的接点接入飞行车的发动装置。
Ha'nyu发现因为某些元件的方向不小心发生了改变,电路板可能处于断路的状态。她准备通过计算,旋转最少数量的元件,使电源与发动装置通过若干条短缆相连。不过,电路的规模实在是太大了,Ha'nyu并不擅长编程,希望你能够帮她解决这个问题。
输入格式
输入文件包含多组测试数据。第一行包含一个整数T 表示测试数据的数目。
对于每组测试数据,第一行包含正整数R 和C,表示电路板的行数和列数。
之后R 行,每行C 个字符,字符是"/"和"\"中的一个,表示标准件的方向。
输出格式
对于每组测试数据,在单独的一行输出一个正整数,表示所需的缩小旋转次数。
如果无论怎样都不能使得电源和发动机之间连通,输出NO SOLUTION。
样例输入
1 3 5 \\/\\ \\/// /\\\\
样例输出
1
数据范围与约定
- 对于40% 的数据,R,C≤5。
对于100% 的数据,R,C≤500,T≤5。
样例解释
样例的输入对应于题目描述中的情况。
只需要按照下面的方式旋转标准件,就可以使得电源和发动机之间连通。
思路:将网格交点当成点,然后就是从起点(1,1)到终点(r+1,c+1)的最短路径。
当前点与下一个点之间有线连接时,边权=0,没有时边权=1,
我们知道bfs要求队列的单调性和两段性,如果我们直接bfs,会导致有些总边权大的在边总权小的前面,单调性被破坏(单调性十分重要),那么我们肯定想到把边权小的往前面塞,边权大的往后面塞,这样就用到了双端队列。由于权值只会不变或者+1,序列一定维持两段性也就是直接往队列头加入和队列尾加入不会影响单调性。
另外,只有出队的时候的值才表示这个点的最短路径值(需要将所有当前边权的点跑一遍,将所有生成的下一个点按大小塞入队列,若一个点出现多次,队头取出的肯定最小) 。
这题由于权值只有0、1,导致了我们可以用双端队列控制其单调性,当然也可以直接用优先队列,用优先队列的话,基本就是堆优化的 Dijkstra
双端队列:
#include<bits/stdc++.h> using namespace std; int t; int r,c; char maps[505][505]; int vis[505][505]; int ways[4][2] = {1,1,-1,-1,-1,1,1,-1}; void init() { scanf("%d %d",&r,&c); char s[505]; for(int i=1; i<=r; i++) { scanf("%s",s); for(int j=1; j<=c; j++) { maps[i][j] = s[j-1]; } } } struct Node { int x,y; Node(int x=0,int y=0):x(x),y(y) {} }; bool check(int x,int y) { if(x < 1 || x > r + 1 || y < 1 || y > c + 1) return 0; return 1; } bool bfs() { deque<Node>que; while(!que.empty()) que.pop_back(); que.push_back(Node(1,1)); memset(vis,0x3f,sizeof(vis)); vis[1][1] = 0; while(!que.empty()) { Node tmp = que.front(); que.pop_front(); if(tmp.x == r+1 && tmp.y == c+1)return 1; for(int i=0; i<4; i++) { int xx = tmp.x + ways[i][0]; int yy = tmp.y + ways[i][1]; if(check(xx,yy)) { char t = i <= 1? '\\' : '/'; bool val = (maps[min(xx,tmp.x)][min(yy,tmp.y)] != t); if(val + vis[tmp.x][tmp.y] < vis[xx][yy]) { vis[xx][yy] = val + vis[tmp.x][tmp.y]; if(val) que.push_back(Node(xx,yy)); else que.push_front(Node(xx,yy)); } } } } return 0; } int main() { scanf("%d",&t); while(t--) { init(); if(!bfs()) printf("NO SOLUTION\n"); else printf("%d\n",vis[r+1][c+1]); } }
优先队列:
#include<bits/stdc++.h> using namespace std; int r,c; int t; char maps[505][505]; int vis[505][505]; int ways[4][2] = {1,1,-1,-1,-1,1,1,-1}; void init() { scanf("%d %d",&r,&c); char s[505]; for(int i=1; i<=r; i++) { scanf("%s",maps[i]+1); } } struct Node { int val; int x,y; Node(int val,int x=0,int y=0):val(val),x(x),y(y) {} }; bool operator<(const Node a,const Node b) { return a.val > b.val; } bool check(int x,int y) { if(x < 1 || x > r + 1 || y < 1 || y > c + 1) return 0; return 1; } bool bfs() { priority_queue<Node,vector<Node> >que; while(!que.empty())que.pop(); memset(vis,0x3f,sizeof(vis)); que.push(Node(0,1,1)); que.push(Node(1,1,1)); while(!que.empty()) { Node tmp = que.top(); que.pop(); if(vis[tmp.x][tmp.y] != 0x3f3f3f3f)continue; vis[tmp.x][tmp.y] = tmp.val; if(tmp.x == r+1 && tmp.y == c+1)return 1; for(int i=0;i<4;i++) { int xx = tmp.x + ways[i][0]; int yy = tmp.y + ways[i][1]; if(!check(xx,yy))continue; char t = i <= 1 ? '\\' : '/'; bool val = maps[min(xx,tmp.x)][min(yy,tmp.y)] != t; if(val + vis[tmp.x][tmp.y] < vis[xx][yy]) { que.push(Node(val+vis[tmp.x][tmp.y],xx,yy)); } } } return 0; } int main() { scanf("%d",&t); while(t--) { init(); if(bfs())printf("%d\n",vis[r+1][c+1]); else printf("NO SOLUTION\n"); } }