思路:其实这道题的就是求S和所有A之间能互通的最小的路,其实就是最小生成树,把S当做A来看待,那么就是要记录每个A之间的路,用BFS暴力即可。记录下S和A出现的位置,并把它们编号,最后用edge数组存下。之后就是最小生成树模板题了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
int edge[109][109];
int dis[109]; //记prime函数中不在最小生成树的点到最小生成树的最短距离
bool vis[109][109];
bool vi[109]; //记prime函数中有有多少个点已经在最小生成树中
int v[209][209]; //存S和A的编号
char mazi[59][59];
int _move[4][2]= {{-1,0},{0,1},{1,0},{0,-1}};
int n,m;
int num; //记有多少个A和S
int prime()
{
memset(vi,false,sizeof(vi));
int i,j;
for(i=1; i<num; i++)
dis[i]=edge[1][i];
vi[1]=true;
int minc;
int p;
int ans=0;
for(i=2; i<num; i++)
{
minc=inf;
for(j=1; j<num; j++)
if(!vi[j]&&minc>dis[j])
minc=dis[p=j];
ans+=minc;
vi[p]=true;
for(j=1; j<num; j++)
{
if(!vi[j]&&dis[j]>edge[p][j])
dis[j]=edge[p][j];
}
}
return ans;
}
struct node //存的是S和A的位置
{
int step;
int x;
int y;
} nn[250],p,h;
void bfs()
{
int i,j;
int nx,ny;
for(i=1; i<num; i++) //从第一个点开始遍历
{
queue<node>s;
memset(vis,false,sizeof(vis));
p.x=nn[i].x;
p.y=nn[i].y;
p.step=0;
vis[p.x][p.y]=true;
s.push(p);
while(s.size())
{
h=s.front();
s.pop();
if(v[h.x][h.y]!=0)
edge[i][v[h.x][h.y]]=edge[v[h.x][h.y]][i]=h.step;
for(j=0; j<4; j++)
{
nx=h.x+_move[j][0];
ny=h.y+_move[j][1];
if(nx<=0||nx>m||ny<=0||ny>n)
continue;
if(vis[nx][ny])
continue;
if(mazi[nx][ny]=='#')
continue;
vis[nx][ny]=true;
p.x=nx;
p.y=ny;
p.step=h.step+1;
s.push(p);
}
}
}
}
int main()
{
char s[40];
int t;
int i,j;
int ans;
scanf("%d",&t);
while(t--)
{
memset(v,0,sizeof(v));
scanf("%d%d",&n,&m);
num=1; //编号从1开始
gets(s); //这里是最坑的地方!!切记切记!!!
for(i=1; i<=m; i++)
{
gets(mazi[i]+1);
for(j=1; j<=n; j++)
{
if(mazi[i][j]=='A'||mazi[i][j]=='S')
{
v[i][j]=num;
nn[num].x=i;
nn[num].y=j;
num++;
}
}
}
bfs();
ans=prime();
printf("%d\n",ans);
}
return 0;
}