1. 题目大意
在一个nrow行ncolumn列的迷宫中,有可行走的通路空格’ ’,不可行走的墙’#’,还有两种英文字母A和S,现在从S出发,要求用最短的路径L连接所有字母,输出这条路径L的总长度。一格的长度为1,而且移动的方法只有上、下、左、右,所以在无任何墙的情况下(但“墙#”是必须考虑的,这里只是为了说明)任意两个字母之间的距离就是直接把横坐标之差加上纵坐标之差。注意的是,可行的路为字母和空格不可行的路为 #和矩阵范围之外。
2. 题目分析
根据题意的“分离”规则,重复走过的路不再计算,因此当使用prim算法求L的长度时,根据算法的特征恰好不用考虑这个问题(源点合并很好地解决了这个问题),L就是最少生成树的总权值W,由于使用prim算法求在最小生成树,因此无论哪个点做起点都是一样的,(通常选取第一个点),因此起点不是S也没有关系,所以所有的A和S都可以一视同仁,看成一模一样的顶点就可以了。最后要注意的就是字符的输入cin和scanf不读入空字符(包括空格,换行等),gets读入空格,但不读入换行符。剩下的问题关键就是处理任意两字母间的最短距离,由于存在了“墙#”,这个距离不可能单纯地利用坐标加减去计算,必须额外考虑,推荐用BFS(广搜、宽搜),这是本题的唯一难点,因为prim根本直接套用就可以了。
求任意两字母间的最短距离时不能直接用BFS求:
1、必须先把矩阵中每一个允许通行的格看做一个结点(就是在矩阵内所有非#的格都作为图M的一个顶点),对每一个结点i,分别用BFS求出它到其他所有结点的权值(包括其本身,为0),构造结点图M;
2、然后再加一个判断条件,从图M中抽取以字母为顶点的图,进而构造字母图N;
这个判定条件就是当结点图M中的某点j为字母时,把i到j的权值再复制(不是抽离)出来,记录到字母图N的邻接矩阵中;
3、剩下的就是对字母图N求最小生成树了。
3. 代码
#include<stdio.h>
#include<string.h>
#include<queue>
#define MAXN 55
#define MAXINT 999999999
typedef struct myNode
{
int x;
int y;
int step;
}Node;
char map[MAXN][MAXN];
Node node[2*MAXN];
int nrow, ncolumn, nvertex;
int g[2*MAXN][2*MAXN], id[MAXN][MAXN],move[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
using namespace std;
void init()
{
int i,j;
for(i=0;i<2*MAXN;i++)
for(j=0;j<2*MAXN;j++)
(i==j)? (g[i][j]=0) : (g[i][j]=MAXINT);
}
void bfs(Node s)
{
inti,nx,ny,step;
intvis[MAXN][MAXN]={{0}};
Nodetemp,p;
queue<Node>que;
que.push(s);
vis[s.x][s.y]=1;
while(!que.empty())
{
temp=que.front();
que.pop();
for(i=0;i<4;i++)
{
nx=temp.x+ move[i][0];
ny=temp.y+ move[i][1];
step=temp.step;
if(!vis[nx][ny]&& nx>=0 && nx<ncolumn && ny>=0 &&ny<nrow)
{
if('A'==map[nx][ny]|| 'S'==map[nx][ny])
{
p.x=nx;
p.y=ny;
p.step=++step;
que.push(p);
vis[nx][ny]=1;
g[id[s.x][s.y]][id[nx][ny]]=g[id[nx][ny]][id[s.x][s.y]]=step;
}
if(''==map[nx][ny])
{
p.x=nx;
p.y=ny;
p.step=++step;
que.push(p);
vis[nx][ny]=1;
}
}
}
}
}
void generateGraph()
{
int i,j;
for(i=0;i<nrow;i++)
gets(map[i]);
nvertex=0;
memset(id,0,sizeof(id));
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
if('A'==map[i][j]|| 'S'==map[i][j])
{
node[nvertex].x=i;
node[nvertex].y=j;
node[nvertex].step=0;
id[i][j]=nvertex++;
}
}
}
for(i=0;i<nvertex;i++)
bfs(node[i]);
}
int prim(int start)
{
intv,i,distance;
intvisited[2*MAXN]={0},dis[2*MAXN];
for(i=0;i<nvertex;i++)
dis[i]=MAXINT;
dis[start]=0;
v=start;
while(!visited[v])
{
visited[v]=1;
for(i=0;i<nvertex;i++)
{
if(!visited[i] && dis[i]>g[v][i])
dis[i]=g[v][i];
}
distance=MAXINT;
for(i=0;i<nvertex;i++)
{
if(!visited[i] && dis[i]<distance)
{
distance=dis[i];
v=i;
}
}
}
distance=0;
for(i=0;i<nvertex;i++)
distance+=dis[i];
returndistance;
}
int main()
{
int T;
char str[100];
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&ncolumn,&nrow);
gets(str);
init();
generateGraph();
printf("%d\n",prim(0));
}
return 0;
}