传送门:洛谷P2243
题目描述
分析
初步判断,是道最短路的题.
首先就是建图了,对于电路板上的每一对角线,令与读入方向相同的路径边权为0,方向相反的边权为1.
由于只能走斜线,根据网格图的性质可知横纵坐标之和为奇数的点是到不了的,默认起点为
(
0
,
0
)
(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;
}