题目大意:给出一个迷宫,迷宫里面有一些外星人,要求找到所有外星人,给出搜索源点S及外星人A,在S点和A点可以分叉走,问找到所有外星人的最短路径是多少。
思路分析:把S点和所有A点建成一个完全图,而边的权值就是两个顶点的最短距离,这里用bfs求得,在这道题中,我先是把S点和所有的A点用一个二维数组存了下来,以方便bfs查找建图,还有一点要说明的事(就是我做题犹豫的事情啦),在建立任意两个A点的边的时候,我们在搜索距离时,可能路过S点,这时我们不用管S,就把S点当做一个空格可以行走的点就好了。
代码实现:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
char str[55][55];
int p[105][105],dis[105],visit[105][105],sa[105][5],vis[105];
int dir[4][2]={1,0,-1,0,0,-1,0,1},X,Y,cnt;
struct Node{
int x,y,step;
Node(int xx=0,int yy=0,int ss=0):x(xx),y(yy),step(ss){}
};
queue<Node>q;
int bfs(int x1,int y1,int x2,int y2){
//printf("bfs %d %d %d %d\n",x1,y1,x2,y2);
while(!q.empty()) q.pop();
Node head(x1,y1,0);
Node next;
memset(visit,0,sizeof(visit));
visit[x1][y1]=1;
q.push(head);
while(!q.empty()){
//printf("*|");
head=q.front();
q.pop();
for(int i=0;i<4;i++){
next.x=head.x+dir[i][0];
next.y=head.y+dir[i][1];
if(next.x<0||next.x>=Y||next.y<0||next.y>=X) continue;
if(str[next.x][next.y]=='#'||visit[next.x][next.y]==1) continue;
//printf("%d %d\n",next.x,next.y);
visit[next.x][next.y]=1;
next.step=head.step+1;
q.push(next);
if(next.x==x2&&next.y==y2) return next.step;
}
}
return 1e9;
}
void Prim(){
int k,sum=0,min_c;
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=0;i<cnt;i++)
dis[i]=p[0][i];
for(int i=1;i<cnt;i++){
min_c=1e9,k=-1;
for(int j=0;j<cnt;j++){
if(vis[j]==0&&dis[j]<min_c){
min_c=dis[j];
k=j;
}
}
if(k==-1) break;
vis[k]=1;
sum+=min_c;
for(int j=0;j<cnt;j++){
if(vis[j]==0&&dis[j]>p[k][j])
dis[j]=p[k][j];
}
}
printf("%d\n",sum);
}
int main(){
int n;
char t[1000];
scanf("%d",&n);
while(n--){
scanf("%d%d",&X,&Y);
cnt=0;
gets(t);
for(int i=0;i<Y;i++){
gets(str[i]);
for(int j=0;j<X;j++){
if(str[i][j]=='S'||str[i][j]=='A'){
sa[cnt][0]=i,sa[cnt][1]=j;
cnt++;
}
}
}
for(int i=0;i<cnt;i++){
for(int j=i;j<cnt;j++){
if(i==j) p[i][j]=1e9;
else{
int val=bfs(sa[i][0],sa[i][1],sa[j][0],sa[j][1]);
//printf("val %d\n",val);
p[i][j]=p[j][i]=val;
}
}
}
/*for(int i=0;i<cnt;i++){
for(int j=0;j<cnt;j++)
printf("%d ",p[i][j]);
printf("\n");
}*/
Prim();
}
}