You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
3.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}