题目:http://poj.org/problem?id=3026
AC代码(C++):
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <vector>
#include <queue>
#include <math.h>
#include <string>
#include <string.h>
#include <bitset>
#define INF 0xfffffff
#define MAXN 55
using namespace std;
struct POINT{
int x,y;
int step;
}from,to;
int n;
int x,y;
char g[MAXN][MAXN];
int map[MAXN*2][MAXN*2];
int dis[MAXN*2];
bool vis[MAXN*2];
int xy[MAXN][MAXN];
bool vist[MAXN][MAXN];
int dirx[4] = {0,1,0,-1};
int diry[4] = {1,0,-1,0};
void bfs(int sx, int sy) {
queue<POINT> q;
memset(vist, false, sizeof(vist));
POINT ss;
ss.x = sx;
ss.y = sy;
ss.step = 0;
vist[sx][sy] = true;
q.push(ss);
while (!q.empty()) {
from = q.front();
q.pop();
if(g[from.y][from.x]=='A'||g[from.y][from.x]=='S')map[xy[from.x][from.y]][xy[sx][sy]] = map[xy[sx][sy]][xy[from.x][from.y]] = from.step;
for(int i = 0; i < 4; i++){
to.x = from.x + dirx[i];
to.y = from.y + diry[i];
if (vist[to.x][to.y] == false && g[to.y][to.x] != '#') {
vist[to.x][to.y] = true;
to.step = from.step + 1;
q.push(to);
}
}
}
}
int Prim(){
int ans = 0;
for(int i=0;i<n;i++)dis[i]=map[0][i];
memset(vis,false,sizeof(vis));
vis[0]=1;
for(int i=1;i<n;i++){
int next,tmp = INF;
for(int j=0;j<n;j++){
if(!vis[j]&&tmp>dis[j]){
tmp=dis[j];
next=j;
}
}
ans += tmp;
vis[next]=1;
for(int j=0;j<n;j++){
if(!vis[j]&&dis[j]>map[next][j])
dis[j]=map[next][j];
}
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
for(int tt = 0; tt < t; tt++){
n = 0;
scanf("%d %d\n",&x,&y);
for(int i = 0; i < y; i++){
gets(g[i]);
for(int j = 0; j < x; j++)if(g[i][j]=='A'||g[i][j]=='S'){
xy[j][i] = n;
n++;
}
}
for(int i=0;i<y;i++){
for(int j=0;j<x;j++){
if(g[i][j] == 'S' || g[i][j] == 'A'){
bfs(j,i);
}
}
}
printf("%d\n",Prim());
}
}
总结: 这题技术上不难, 但是有点坑. 对于给定的迷宫, 首先找出所有的A或者S, 编号并保存位置. 然后求出两两间的距离, 构造完全图. 最后对这个完全图用Prim算法计算最小生成树, 所得权值既是所求. 看起来很简单的样子只需要BFS + Prim就能搞定, 但是一定要注意对BFS的优化. 一开始我用的BFS模板是在每次pop的时候操作vis数组, 然后就一直TLE, 直到我把这个vis操作放到push的后面...浪费我2个小时来调...