这题其实就是最小生成树(MST)
题目中说的“每当一个外国人被同化,或者在搜索开始时,该群体可能会分裂成两个或更多的群体”,就是可以延伸出多条路径的意思。
先用BFS将两点之间的距离算出,复杂度O(people*n*m)
然后一趟MST就解决了,复杂度O(people^2)。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int flg[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int T,n,m,id,hd,tl,ans,mp[55][55],cst[105][105],lwcst[105];
struct xcw{
int x,y,t;
xcw(){x=0;y=0;t=0;}
xcw(int a,int b,int c){x=a,y=b,t=c;}
}a[105],que[2505];
bool vis[55][55],tre_vis[105];
bool check(int x,int y){
if(x<1||x>n||y<1||y>m) return 0;
if(mp[x][y]==-1||vis[x][y]) return 0;
return 1;
}
void BFS(int x,int y,int t){
hd=0;que[tl=1]=xcw(x,y,0);vis[x][y]=1;
while(hd^tl){
x=que[++hd].x,y=que[hd].y;
for(int i=0;i^4;i++){
int xx=x+flg[i][0],yy=y+flg[i][1];
if(check(xx,yy)){
que[++tl]=xcw(xx,yy,que[hd].t+1);vis[xx][yy]=1;
if(mp[xx][yy]>0) cst[t][mp[xx][yy]]=que[tl].t;
}
}
}
}
void prim(){
ans=0;
memset(tre_vis,0,sizeof(tre_vis));
tre_vis[1]=1;
for(int i=1;i<=id;i++) lwcst[i]=cst[i][1];
for(int i=1;i^id;i++){
int min=1e9,k=0;
for(int j=1;j<=id;j++)
if(!tre_vis[j]&&lwcst[j]<min) min=lwcst[j],k=j;
tre_vis[k]=1;ans+=min;
for(int j=1;j<=id;j++)
if(!tre_vis[j]&&lwcst[j]>cst[j][k]) lwcst[j]=cst[j][k];
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&n);id=0;
scanf("%*[^\n]");//这题很坑,在这之后有很多多余字符,所以直接跳过这一行
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch=getchar();
if(ch=='A'||ch=='S') a[++id]=xcw(i,j,0),mp[i][j]=id;else
if(ch==' ') mp[i][j]=0;else mp[i][j]=-1;
}
getchar();
}
for(int i=1;i<=id;i++){
memset(vis,0,sizeof(vis));
BFS(a[i].x,a[i].y,i);
}
prim();
printf("%d\n",ans);
}
return 0;
}