#include using namespace std; typedef pair 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, greater> 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; }