G - Borg Maze (Prim&BFS)
题意:给一个图,起点S,求遍历到所有‘A’的最小距离之和.每次走到一个‘A’相当于这个’A’是新的起点’S‘,很显然会想到树,新的子结点作为根结点继续往下搜索.所以此题为最小生成树问题。具体看代码。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
int r,c;
const int N=205,inf=0x3f3f3f3f;
char mp[N][N];
int pos[N][N],cnt=0,vis[N][N],dis[N][N];//pos[i][j]记录S或A的位置,vis[i][j]即作为标记也作为距离使用。
struct zb{
int x,y;
}now;
int dw[4][2]={0,1,0,-1,1,0,-1,0};
void bfs(int sx,int sy){
queue<zb>q;
memset(vis,-1,sizeof vis);//初始化-1保证起点到自己的距离为0.
q.push({sx,sy}),vis[sx][sy]=0;
while(q.size()){
now=q.front();q.pop();
if(pos[now.x][now.y]) dis[pos[sx][sy]][pos[now.x][now.y]]=vis[now.x][now.y];
for(int i=0;i<4;i++){
int nx=now.x+dw[i][0],ny=now.y+dw[i][1];
if(vis[nx][ny]==-1&&mp[nx][ny]!='#'&&nx>=1&&nx<=r&&ny>=1&&ny<=c)
{
vis[nx][ny]=vis[now.x][now.y]+1;
q.push({nx,ny});
}
}
}
}
int prim(){
int jg[N]={},w[N]={},ans=0;
jg[1]=1;//任取一个点开始贪心操作.
for(int i=2;i<=cnt;i++) w[i]=dis[1][i];//初始化.
for(int i=2;i<=cnt;i++)
{
int mn=inf,id=0;
for(int j=1;j<=cnt;j++){ //找到距离集合最近的邻居.
if(!jg[j]&&w[j]<mn){
mn=w[j];
id=j;
}
}
if(mn==inf) break;
ans+=mn;
jg[id]=1;
for(int j=1;j<=cnt;j++)
if(!jg[j]&&dis[id][j]<w[j]) //每次集合中加入一个点就用这个点对其他点松弛.
w[j]=dis[id][j];
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
cnt=0,memset(dis,0,sizeof dis),memset(pos,0,sizeof pos);
scanf("%d%d",&c,&r);
char ch;
while((ch=getchar())!='\n') ;//r,c后有空格去除空格.
for(int i=1;i<=r;i++){
gets(mp[i]+1);//为了读取空格.
for(int j=1;j<=c;j++){
if(mp[i][j]=='S'||mp[i][j]=='A')
pos[i][j]=++cnt;
}
}
for(int i=1;i<=r;i++)
for(int j=1;j<=r;j++)
if(pos[i][j]) bfs(i,j);
printf("%d\n",prim());
}
return 0;
}