解析:给定一个迷宫,bfs求字母间的距离即边的权值,再prim求最小生成树的权值和即为本题答案。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 105;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int e[N][N], dis[N], b[N][N];
char map[N][N];
bool book[N][N], visit[N];
struct node{
int x, y, step;
};
int n, m;
void bfs(int s, int x, int y){
memset(book, false, sizeof(book));
node p, q;
queue<node> Q;
p.x = x, p.y = y;
p.step = 0;
Q.push(p);
book[x][y] = true;
while(!Q.empty()){
p = Q.front();
Q.pop();
if(map[p.x][p.y] >= 'A' && map[p.x][p.y] <= 'Z')
e[s][b[p.x][p.y]] = p.step;
for(int i = 0; i < 4; ++i){
q.x = p.x + dir[i][0];
q.y = p.y + dir[i][1];
if(q.x < m && q.x >= 0 && q.y >= 0 && q.y < n && book[q.x][q.y] == false && map[q.x][q.y] != '#'){
book[q.x][q.y] = true;
q.step = p.step + 1;
Q.push(q);
}
}
}
}
int main(){
int T;
scanf("%d", &T);
while(T--){
fill(e[0], e[0] + N*N, INF);
fill(dis, dis + N, INF);
memset(visit, false, sizeof(visit));
scanf("%d%d", &n, &m);
int cnt = 1;
gets(map[0]);
for(int i = 0; i < m; ++i){
gets(map[i]);
for(int j = 0; j < n; ++j)
if(map[i][j] <= 'Z' && map[i][j] >= 'A')
b[i][j] = cnt++;
}
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
if(map[i][j] >= 'A' && map[i][j] <= 'Z')
bfs(b[i][j], i, j);
int sum = 0;
n = cnt - 1;
dis[1] = 0;
for(int i = 0; i < n; ++i){
int u = -1, minn = INF;
for(int j = 1; j <= n; ++j)
if(visit[j] == false && dis[j] < minn){
minn = dis[j];
u = j;
}
if(u == -1) break;
visit[u] = true;
sum += minn;
for(int v = 1; v <= n; ++v)
if(visit[v] == false && dis[v] > e[u][v])
dis[v] = e[u][v];
}
printf("%d\n", sum);
}
return 0;
}