1. 程式人生 > >電路維修 --- 雙端佇列bfs

電路維修 --- 雙端佇列bfs

傳送門:洛谷P2243


題目描述

這裡寫圖片描述


分析

初步判斷,是道最短路的題.
  首先就是建圖了,對於電路板上的每一對角線,令與讀入方向相同的路徑邊權為0,方向相反的邊權為1.
  由於只能走斜線,根據網格圖的性質可知橫縱座標之和為奇數的點是到不了的,預設起點為 ( 0 , 0 )

(0, 0) ,對此,可以去掉一半的邊(根本就到不了),同時也可以直接判斷無解的情況
  跑圖的話,dijkstra + heap,和經過優化的spfa(關於spfa,他$ \cdots $)應該是能過的,但由於邊權只有0和1,所以只要考慮用雙端佇列的bfs,即可(類似於spfa的SLF優化), 若邊權為1,則將其放入隊尾,否則置於隊首,要注意的是,一個點可能多次入隊


程式碼

#include <cstdio>
#include <cstdlib>
#include
<cstring>
#include <deque> #define IL inline using namespace std; IL int read() { char c = getchar(); int sum = 0 ,k = 1; for(;'0' > c || c > '9'; c = getchar()) if(c == '-') k = -1; for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c -
'0'; return sum * k; } int to[502005], nxt[502005], val[502005]; int last[251005]; int cnt; IL void add(int u, int v, int w) { //printf("%d %d %d\n", u, v, w); to[++cnt] = v; nxt[cnt] = last[u]; val[cnt] = w; last[u] = cnt; to[++cnt] = u; nxt[cnt] = last[v]; val[cnt] = w; last[v] = cnt; } int S, T; int n, m; int dis[251005]; IL int turn(int x, int y) { return x * (m + 1) + y + 1; } IL void bfs(int u) { memset(dis, -1, sizeof(dis)); dis[u] = 0; deque<int>Q; Q.push_back(u); if(S == T) { printf("0\n"); return ; } for(; !Q.empty();) { u = Q.front(); Q.pop_front(); for(int i = last[u], v; (v = to[i]); i = nxt[i]) if(dis[v] == -1 || dis[u] + val[i] < dis[v]) { dis[v] = dis[u] + val[i]; //printf("%d %d %d %d\n", u, v, dis[u], dis[v]); if(v == T) { printf("%d\n", dis[v]); return ; } if(!val[i]) Q.push_front(v); else Q.push_back(v); } } } int main() { for(int k = read(); k; --k) { cnt = 0; memset(last, 0, sizeof(last)); n = read(); m = read(); char c; for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) { scanf(" %c", &c); if((i + j) & 1) add(turn(i, j + 1), turn(i + 1, j), c == '\\'); else add(turn(i, j), turn(i + 1, j + 1), c == '/'); } if((n + m) & 1) { printf("NO SOLUTION\n"); continue; } S = 1; T = turn(n, m); bfs(S); } return 0; }