题意:在迷宫中找存在的外星人A撒。。开始是一个组织找,后来这个组织可以分裂成
很多组。求找到所有外星人的最小步数。(分裂后,步数计算为所有组织的步数和)
思路:因为要保证每个外星人A都找到,加上组织所在起始点S,求最小步数。即求图中
n个点的最小生成树(n=外星人的个数+1)。
bfs找每两点间的距离。
1、这题要注意时间复杂度。
开始预处理时把所有外星人和组织起点横纵坐标记录后。用了两个for循环,来找每两点的
距离。这样要调用n*n次bfs去搜状态,结果tle。其实每次重复搜没必要。
将n*n复杂度可以降到n。也就是遍历n个点,以其中每个点作起点一次,来搜到达其他各点
的最短距离。
2、这题要注意数组大小
外星人最多100,加上组织起点S一共101个点。
数组开小就wa了。
3、这题读入迷宫行列后不能用getchar,因为后面不止是单纯的回车。还有多余空格。
要用gets()吃掉所有。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int x,y;
int step;
};
char m[55][55];
int r[110],c[110],ans,rear,x,y;
int edge[110][110],dis[110];
bool vis[110];
bool v[55][55];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
queue<node> Q;
void dist(int i)
{
while(!Q.empty())
Q.pop();
node a,b,tmp;
int num=0;
a.x=r[i],a.y=c[i];
a.step=0;
Q.push(a);
v[r[i]][c[i]]=1;
while(!Q.empty())
{
tmp=Q.front();
Q.pop();
for(int k=0;k<rear;k++)
{
if(tmp.x==r[k] && tmp.y==c[k])
{
edge[k][i]=edge[i][k]=tmp.step;
num++;
break;
}
}
if(num==rear)
break;
for(int k=0;k<4;k++)
{
b.x=tmp.x+dx[k];
b.y=tmp.y+dy[k];
b.step = tmp.step+1;
if(b.x>=1 && b.x<=y && b.y>=1&&b.y<=x && m[b.x][b.y]!='#'&& !v[b.x][b.y])
{
v[b.x][b.y]=1;
Q.push(b);
}
}
}
}
void prim()
{
int u=0;
for(int i=1;i<rear;i++)
{
dis[i]=edge[u][i];
}
vis[u]=1;
for(int i=1;i<rear;i++)
{
int minc = INF;
for(int j=0;j<rear;j++)
{
if(!vis[j] && dis[j]<minc)
{
u=j;
minc=dis[j];
}
}
ans+=minc;
vis[u]=1;
for(int j=0;j<rear;j++)
{
if(!vis[j] && edge[u][j]<dis[j])
dis[j]=edge[u][j];
}
}
}
int main()
{
int T,sx,sy;
char shit[50];
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
scanf("%d%d",&x,&y);
gets(shit);
for(int i=1;i<=y;i++)
gets(m[i]+1);
rear=0;
for(int i=1;i<=y;i++)
{
for(int j=1;j<=x;j++)
{
if(m[i][j]=='S')
{
sx=i;
sy=j;
}
else if(m[i][j]=='A')
{
r[rear]=i;
c[rear++]=j;
}
}
}
r[rear]=sx;
c[rear++]=sy;
for(int i=0;i<rear;i++)
{
memset(v,0,sizeof(v));
dist(i);
}
ans=0;
prim();
printf("%d\n",ans);
}
return 0;
}