思路:
从s出发(看作有很多人)意思可以从多个方向走,去寻找到达A的最短路径。如找到一个A,那么可以从当前位置出发这时候步数又为0了,又去寻找其他的A。
也可以直接暴力求解每个字母到达其他字母的路径进行建图,就从每个字母出发,进行多次BFS求解即可。
code :
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 55, M = N * N;
int n, m, t, sx, sy, cnt, mcnt, path[N][N], id[N][N], p[N]; //代表某个字母到达(i, j)的距离
char g[N][N];
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, 1, -1, 0};
struct Node {
int x, y, sx, sy, d;
Node(int x, int y, int sx, int sy, int d): x(x), y(y), sx(sx), sy(sy), d(d){}
bool operator < (const Node&o) const {
return d > o.d;
}
};
struct E {
int u, v, w;
bool operator < (const E&o) const {
return w < o.w;
}
} e[M];
int find(int x){return x == p[x] ? x : (p[x] = find(p[x]));}
void bfs() {
priority_queue<Node> q;
path[sx][sy] = 0;
id[sx][sy] = ++cnt; //给每个字母标号
q.push(Node(sx, sy, sx, sy, 0));
while (!q.empty()) {
Node t = q.top();
q.pop();
for (int i = 0; i < 4; i++) {
int fx = t.x + dx[i];
int fy = t.y + dy[i];
if (fx >= 0 && fy >= 0 && fx < n && fy < m && g[fx][fy] != '#') {
if (t.d + 1 < path[fx][fy]) {
if (t.sx == fx && t.sy == fy) continue;//避免自己与自己连边
path[fx][fy] = t.d + 1;
if (g[fx][fy] == 'A') {
q.push(Node(fx, fy, fx, fy, 0));
if (!id[fx][fy]) id[fx][fy] = ++cnt;
//添加边
e[++mcnt].u = id[t.sx][t.sy];
e[mcnt].v = id[fx][fy];
e[mcnt].w = t.d + 1;
} else {
q.push(Node(fx, fy, t.sx, t.sy, path[fx][fy]));
}
}
}
}
}
}
int main() {
scanf("%d", &t);
while (t--) {
memset(path, 0x3f, sizeof(path)); cnt = mcnt = 0;
memset(id, 0, sizeof(id));
scanf("%d%d", &m, &n);
gets(g[0]); //消除上面的换行
for (int i = 0; i < n; i++) gets(g[i]);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == 'S') sx = i, sy = j;
}
}
bfs(); //确定字母之间的关系
int ans = 0;
sort(e + 1, e + 1 + mcnt);
for (int i = 1; i <= cnt; i++) p[i] = i; //初始化并查集
for (int i = 1; i <= mcnt; i++) {
int fu = find(e[i].u), fv = find(e[i].v);
if (fu != fv) {
ans += e[i].w;
p[fu] = fv;
}
}
printf("%d\n", ans);
}
return 0;
}