Files
python/TangDou/AcWing/DequeBfs/175_FeiQi_Dijkstra_JianTu.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

112 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
/*
举栗子: 以3行5列为例,共3*5=15个格子
是4行*6列=24个点
推广公式化:(n+1)*(m+1)
*/
const int N = 510 * 510;
const int M = 4 * N; // 1个格子里面有4条边,分别为 a->b,b->a,c->d,d->c
const int INF = 0X3f3f3f3f;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int getNum(int x, int y) {
/*
* 按点看 ,为 0,1,2,3,4,...,m
* 按格子看,为 1,2,3,4,...,m
即按点看,每行m+1个点
推广公式化: 编号 = 行号(可以从0开始,也可以从1开始)*列的数量 + 列号
*/
return x * (m + 1) + y; //按点看,共m+1列
}
int dijkstra() {
//初始化最短距离
memset(dist, 0x3f, sizeof dist);
dist[0] = 0; // 0号点的最短距离是0
// greater<>()小顶层堆
priority_queue<PII, vector<PII>, greater<PII>> q;
q.emplace(0, 0); //注意:先是距离,后是序号!之所以这样设计,是因为小顶堆的排序是默认安排PII的第一维x进行由小到大
while (q.size()) {
auto t = q.top();
q.pop();
int u = t.second, distance = t.first;
//如果已经走过,不需要再尝试
if (st[u]) continue;
//标识走过
st[u] = true;
//枚举每个出边
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (dist[j] > distance + w[i]) { //在原距离distanc基础上,再走w[i]后可以到达j,如果这样走近,则更新dist[j]
dist[j] = distance + w[i];
q.emplace(dist[j], j); //将j加入队列,继续扩展
}
}
}
//计算最后一个坐标位置对应的节点,它离起点的最短距离是多少
return dist[getNum(n, m)];
}
signed main() {
//加快读入
cin.tie(0), ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--) {
//还原是否走过的状态st=false
memset(st, false, sizeof st);
//多组测试数据,清空邻接表
memset(h, -1, sizeof h);
idx = 0;
// n行m列
cin >> n >> m;
//读入数据+建图
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
char op;
cin >> op;
//现在读入的是当前(i,j)坐标的格子中操作符
/*
点坐标(0,0) 点坐标(0,1) 点坐标(i-1,j-1) 点坐标(i-1,j)
格子坐标:(1,1) => 格子坐标:(i,j)
点坐标(1,0) 点坐标(1,1) 点坐标(i,j-1) 点坐标(i,j)
*/
int a = getNum(i - 1, j - 1);
int b = getNum(i, j);
int c = getNum(i, j - 1);
int d = getNum(i - 1, j);
// Q:为什么权值定义的是 /:1 \:0 呢?
// A:因为我们描述的是 a->b 的边:
// 如果a->b之间有边,就是左上角到右下角有边, \ , 权值为0.
// 如果a->b之间无边,就是右上角到左下角有边, / , 此时需要把它转过来,权值为1.
int w = op == '/' ? 1 : 0;
add(a, b, w), add(b, a, w); //无向图,双向建边
add(c, d, !w), add(d, c, !w); //取反也建边,模拟01边权的无向图
}
}
//求最短路
int res = dijkstra(); // dijkstra可以处理非负权边的图
if (res == INF)
puts("NO SOLUTION");
else
printf("%d\n", res);
}
return 0;
}