题意:
A代表外星人,从S出发,到达每一个A处,把他们同化,同化之后的A(可以分裂成很多个)可去同化其他A,问把所有外星人同化最少需要多少步(只能上下左右),
思路:
用dfs把每一个A或S到其他的外星人的距离都找到,然后就是最小路问题了
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=505;
int MAX=0x3f3f3f3f;
int n,m,k;
char b[N][N],s1[N];
int map[N][N];
int biao[N][N];
int pre[N*N];
int dx[5]={1,0,0,-1};//遍历的四个方向
int dy[5]={0,1,-1,0};
struct node{
int u,v,w;
}a[N*(N-1)/2];
struct haha{
int x,y;
int step;//步数
}now,next;
int cmp(node x,node y)
{
return x.w<y.w;
}
int find(int x)
{
if(pre[x]==x)
return x;
else
return pre[x]=find(pre[x]);
}
int judge(int u,int v)
{
int fx=find(u);
int fy=find(v);
if(fx!=fy)
{
pre[fy]=fx;
return 1;
}
return 0;
}
void bfs(int x,int y,int ans)
{
memset(biao,0,sizeof(biao));
queue<haha>Q;
now.x=x;
now.y=y;
now.step=0;
biao[x][y]=1;
Q.push(now);//加入队列
while(!Q.empty())
{
now=Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
next.x=now.x+dx[i];
next.y=now.y+dy[i];//感觉自己脑子不太好使的样子,now.y,竟然写成了now.x,无语子
next.step=now.step+1;
int x1,y1;
x1=next.x,y1=next.y;
if(x1>=0&&y1>=0&&x1<n&&y1<m&&biao[x1][y1]==0&&map[x1][y1]!=-1)
{
biao[x1][y1]=1;
Q.push(next);
if(map[x1][y1]>0)
{
a[k].u=ans;
a[k].v=map[x1][y1];
a[k++].w=next.step;
}
}
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
int num=1;
scanf("%d%d",&m,&n);
memset(map,0,sizeof(map));
gets(b[0]);//清除空格
//getchar();//不能用,因为m,n后可能有很多空格
for(int i=0;i<n;i++)
{
gets(b[i]);//输入带有空格的字符串不能用scanf,
}
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(b[i][j]==' ')
map[i][j]=0;
if(b[i][j]=='#')
map[i][j]=-1;
if(b[i][j]=='A'||b[i][j]=='S')
{
map[i][j]=num;
num++;//统计A,S的个数
}
}
}
k=0;//用来计算路径条数
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(map[i][j]>0)
bfs(i,j,map[i][j]);
}
}
for(int i=0;i<=num;i++)//kruskal算法
pre[i]=i;
sort(a,a+k,cmp);
int sum=0;
for(int i=0;i<k;i++)
{
if(judge(a[i].u,a[i].v))
{
sum+=a[i].w;
}
}
//cout<<sum<<endl;
printf("%d\n",sum);
}
return 0;
}