大致的题意:
一个 Y 行 X 列的迷宫,空格表示可通行的路, “#”表示墙 ,不能通行,现在从S出发,要求用最短的路径连接所有的字母A,输出这条路径的长度。
思路:
首先是要构图,但难点在于必须要计算每个字母与字母之间的最短距离,而且图每一个格的长度是1,那么两点的距离就是横坐标之差加上纵坐标之差,
计算两个字母的最短距离可以用BFS(广搜)或DFS(深搜),两个字母的最短距离就是两个字母构成边的权值;
根据题目的意思,走过的重复的路是不会再计算的,所以可以用到 Prim 或 Kruskal 算法来计算。
需要注意的是: 输入的时候一定要去除空格,应为这个问题,WA十几次,
以下是 BFS + PRIM 的做法:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int INF = 100000;
int n , m ,num;//num :表示有多少个字母
int dir[4][2] = {-1 , 0 , 1 , 0 , 0 ,1 , 0 , -1};
int edge[200][200];//图的邻接矩阵
int vis[200][200];//用来记录字母是否被访问过
int lowcost[200];
int post[200][200];//记录是第几个字母。用于构图
char map[55][55];
struct node
{
int x , y;
int dist;
};
void BFS(node s)//求两字母的最短距离
{
memset(vis ,0 ,sizeof(vis));
int i;
node t, tmp;
queue<node> q;
q.push(s);
vis[s.x][s.y] = 1;
while(!q.empty())
{
t = q.front();
q.pop();
for(i = 0 ; i < 4; i++)
{
tmp.x = t.x + dir[i][0];
tmp.y = t.y + dir[i][1];
tmp.dist = t.dist+1;
if(tmp.x >=0 && tmp.y < n && tmp.x < m && tmp.y >=0 )
{
if(!vis[tmp.x][tmp.y] && map[tmp.x][tmp.y] != '#')
{
vis[tmp.x][tmp.y] = 1;
int x = post[tmp.x][tmp.y];
int y = post[s.x][s.y];
if(map[tmp.x][tmp.y] == 'A' || map[tmp.x][tmp.y] == 'S')
{
edge[x][y] =edge[y][x] = tmp.dist;
// cout << x << " "<< y <<endl;
}
q.push(tmp);
}
}
}
}
return;
}
void PRIM()
{
int i , j , sum = 0;
int visp[200];
for(i = 1 ; i <= num ; i++)
{
lowcost[i] = edge[1][i];
visp[i] = 0;
}
visp[1] = 1;
for(i = 2 ; i <= num ;i++)
{
int min = INF , u = -1;
for(j = 1 ; j <= num ; j++)
{
if(!visp[j] && lowcost[j] < min)
{
min = lowcost[j];
u = j;
}
}
if(u == -1)
continue;
visp[u] =1;
sum += min;
for(j = 1 ; j <= num ; j++)
{
if(!visp[j] && lowcost[j] > edge[u][j])
{
lowcost[j] = edge[u][j];
}
}
}
printf("%d\n" ,sum);
}
int main()
{
int t;
// freopen("in.txt" ,"r" ,stdin);
// freopen("out.txt" ,"w", stdout);
scanf("%d" ,&t);
while(t--)
{
num = 1;
scanf("%d%d" ,&n ,&m);
char c;
c =getchar();//在这里被坑了好多次。
while(c ==' ')
c = getchar();
int i, j ;
memset(post ,0 ,sizeof(post));
memset(edge , 0 ,sizeof(edge));
for(i = 0 ; i < m ; i++)
{
gets(map[i]);
for(j = 0 ;j < n ; j++)
{
if(map[i][j] == 'S')
post[i][j] = 1;
else if( map[i][j] == 'A' )
post[i][j] = ++num;
}
}
for(i = 0 ; i < m ; i++)
{
for(j = 0 ; j < n ;j++)
{
if(post[i][j] > 0)//大于0的都是字母,计算用这个字母做起点,计算它与其他字母的最短距离。
{
node tmp;
tmp.x = i;
tmp.y = j;
tmp.dist = 0;
BFS(tmp);
}
}
}
PRIM();
}
return 0;
}