题意:
有一个n*m的图,有S,A,#和空格,S可以到达A并且使A变成S,然后这个S又可以去侵染别的A,问A都变成S需要多少步?
分析:
题目相当于求出S和A构成的最小生成树。首先把S和A找出来,枚举每个S和A,然后bfs求一下单点到其他点的最短距离,然后套prim模板就行。
这题有个特别坑的地方就是数字后面可等有多个空格,好坑!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define mp make_pair
const int INF=1000000000;
const int N=500+9;
typedef pair<int,int>pii; //点的坐标 <x,y>
typedef pair<int,pii>piii; //<步数,点>
int w[N][N],low[N];
bool vis[N][N];
char s[N][N];
int n,m;
int dx[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
vector<pii>vec; //存S和A
map<pii,int>id; //给每个S和A编一个号
int sid;
void bfs(pii start)
{
queue<piii>q;
memset(vis,0,sizeof(vis));
q.push(mp(0,start));
vis[start.first][start.second]=1;
while(!q.empty()){
piii p=q.front();q.pop();
int step=p.first,x=p.second.first,y=p.second.second;
for(int i=0;i<4;i++){
int xx=x+dx[i][0],yy=y+dx[i][1];
if(xx<0||yy<0||xx==n||yy==m||vis[xx][yy])continue;
vis[xx][yy]=1;
if(s[xx][yy]=='A'||s[xx][yy]=='S'){
w[id[mp(xx,yy)]][sid]=step+1;continue;
}
if(s[xx][yy]==' ')q.push(mp(step+1,mp(xx,yy)));
}
}
}
int prim(int n)
{
bool vis[111];
memset(vis,0,sizeof(vis));
vis[0]=1;
int ans=0,p=0;
for(int i=0;i<n;i++)low[i]=w[p][i];
for(int i=1;i<n;i++){
int minn=INF;
for(int j=0;j<n;j++)if(!vis[j]&&minn>low[j])minn=low[p=j];
ans+=minn;
vis[p]=1;
for(int j=0;j<n;j++)if(!vis[j]&&low[j]>w[p][j])low[j]=w[p][j];
}
return ans;
}
int main()
{
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&n);
vec.clear();
id.clear();
gets(s[0]); //注意可能有多个空格
for(int i=0;i<n;i++){
gets(s[i]);
for(int j=0;j<m;j++)
if(s[i][j]=='A'||s[i][j]=='S')id[mp(i,j)]=vec.size(),vec.push_back(mp(i,j));
}
for(int i=0;i<vec.size();i++)for(int j=0;j<vec.size();j++)w[i][j]=i==j?0:INF;
for(int i=0;i<vec.size();i++){
sid=id[vec[i]];
bfs(vec[i]);
}
printf("%d\n",prim(vec.size()));
}
return 0;
}