電路維修 --- 雙端佇列bfs
阿新 • • 發佈:2018-11-10
傳送門:洛谷P2243
題目描述
分析
初步判斷,是道最短路的題.
首先就是建圖了,對於電路板上的每一對角線,令與讀入方向相同的路徑邊權為0,方向相反的邊權為1.
由於只能走斜線,根據網格圖的性質可知橫縱座標之和為奇數的點是到不了的,預設起點為
,對此,可以去掉一半的邊(根本就到不了),同時也可以直接判斷無解的情況
跑圖的話,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;
}