Description
有一簇叫做Borg的外星生物,想要扫描整个迷宫建立与其所有下属的联系。迷宫有空格,代表能走的路,有#代表墙壁。有A代表生物,有S代表初始位置。从一个点出发,过程中可以随意分裂,但是行走方式只能是上下左右。然后我们要写一个程序,计算扫描的最短距离。也就是说,当有一个方式连接起来所有的点的时候(题中的A与S),计算这条线的最短距离
Input
第一行为用例组数,每组用例第一行为两个整数m和n表示迷宫的行列数,之后为一m*n矩阵,#代表墙壁,A代表生物,S代表初始位置
Output
对于每组用例,输出连接所有点的线的最短距离
Sample Input
Sample Output
8
11
Solution
最小生成树问题,先用bfs来遍历整张图,从一个点开始,往外扩张,遇到点就把当前扩张的次数记为从起始点到这个点的距离,建立每一个点到其他点的距离矩阵,图建完后直接套用prim的模板即可
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define maxn 300
#define INF 1<<29
struct node
{
int x,y;
};
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0};
char Map[maxn][maxn];//迷宫
bool vis[maxn][maxn];//标记数组
int num[maxn][maxn];//记录点的位置
int cost[maxn][maxn];//记录两点权值
int dis[maxn][maxn];//距离矩阵
int T,n,m,res,ans;
void bfs(int sx,int sy)
{
queue<node>P;
memset(vis,0,sizeof(vis));//初始化
node temp;
temp.x=sx;
temp.y=sy;
P.push(temp);//起点入队
vis[sx][sy]=true;//标记起点
dis[sx][sy]=0;//起点到起点距离为0
while(!P.empty())
{
node t=P.front();//出队
P.pop();
int x=t.x,y=t.y;
if(num[x][y]!=-1)//两点间权值为两点间距离
cost[num[sx][sy]][num[x][y]]=dis[x][y];
for(int i=0;i<4;i++)//四个方向枚举
{
int xx=x+dx[i],yy=y+dy[i];
if(xx<0&&xx>=n&&yy<0&&yy>=m)//超出迷宫区域
continue;
if(vis[xx][yy]||Map[xx][yy]=='#')//该处已被访问或者无法通过
continue;
vis[xx][yy]=true;//可以走则将该步标记
dis[xx][yy]=dis[x][y]+1;//距离加一
node temp;
temp.x=xx;
temp.y=yy;
P.push(temp);//入队
}
}
}
int prim(int s)
{
int d[110];//记录各点到顶点的最短距离
int ans=0;
bool v[110];//标记数组
for(int i=0;i<res;i++)//初始化
{
d[i]=cost[s][i];
v[i]=false;
}
d[s]=0;//起点到起点最短距离为0
v[s]=true;//起点为第一个顶点
for(int i=0;i<res-1;i++)//prim算法
{
int t,m=INF;
for(int j=0;j<res;j++)//从不属于集合中的元素中找到距顶点权值最小的点
if(!v[j]&&m>=d[j])
m=d[t=j];
v[t]=true;//把该点加入集合中
ans+=m;//把边长加到结果中
for(int j=0;j<res;j++)//d[i]记录不属于集合中的元素距顶点的最小距离
if(!v[j]&&d[j]>cost[t][j])
d[j]=cost[t][j];
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
char t[200];
scanf("%d%d",&m,&n);
gets(t);
for(int i=0;i<n;i++)
gets(Map[i]);
res=0;
memset(num,-1,sizeof(num));//初始化
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(Map[i][j]=='S'||Map[i][j]=='A')//记录点的个数
num[i][j]=res++;
if(Map[i][j]=='S')
ans=res-1;
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(Map[i][j]=='S'||Map[i][j]=='A')
bfs(i,j);
printf("%d\n",prim(ans));//从起点开始建树
}
return 0;
}