3026 Borg Maze BFS+prim
/*
题目:
就是所在矩形中有一些外星人,一些人组队打怪去,可以分很多支队,问这些队一共所需的
最少移动步数
分析:
由于可以分很多队,所以可以看做是从起点出发求最小生成树(其实有无起点一样,MST肯定
包括起点),于是问题转换为求最小生成树。怎样处理点与点之间的距离。其实每两个点之间
肯定存在通路,而任两点之间的最小直接距离可以通过bfs求到,于是可以通过枚举所有的点
(即外星人和起点)到另外的点(还是外星人和起点)的距离。具体实现看代码
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define X 102
int map[X][X],ma[X][X],dis[X],n,m,cnt;
int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//方向偏移量
char ch[X][X];
bool use[X][X],visit[X];
struct node //结构体,记录队列中的坐标和移动了的步数
{
int x,y,step;
};
bool check(int x,int y)//检查是否越界
{
if(x<0||y<0||x>=n||y>=m)
return false;
return true;
}
void bfs(int x,int y)
{
memset(use,false,sizeof(use));
node cur;
cur.x = x;
cur.y = y;
cur.step = 0;
queue<node> q; //入队
q.push(cur);
use[x][y] = true;
int cx,cy,step;
int px = x,py = y;
while(!q.empty())
{
cur = q.front(); //队首出队
q.pop(); //删除队首
x = cur.x;
y = cur.y;
step = cur.step;
if(ma[x][y]) //注意到图是无向图 ,ma数组记录的是该坐标下的目标图的顶点下标(从1开始)
map[ ma[x][y] ][ ma[px][py] ] = map[ ma[px][py] ][ ma[x][y] ] = step;
//map数组记录的是目标图中两顶点的距离
for(int i=0;i<4;i++)
{
cx = x+dir[i][0];
cy = y+dir[i][1]; //算出下一次到达的位置
if(check(cx,cy)&&ch[cx][cy]!='#'&&!use[cx][cy])//没有越界,可走的,没走过的
{
use[cx][cy] = true;
cur.x = cx;
cur.y = cy;
cur.step = step+1; //移动距离加一
q.push(cur); //入队
}
}
}
}
void prim() //求最小生成树,图为邻接矩阵map[][],prim标准模板
{
int ans = 0,k,MIN;
memset(visit,false,sizeof(visit));
for(int i=1;i<=cnt;i++)
dis[i] = map[i][1];
visit[1] = true;
for(int i=1;i<cnt;i++)
{
MIN = 10000000;
for(int j=1;j<=cnt;j++)
if(!visit[j]&&dis[j]<MIN)
MIN = dis[k=j];
ans += MIN;
visit[k] = true;
for(int j=1;j<=cnt;j++) //松弛操作
if(!visit[j])
dis[j] = min(dis[j],map[k][j]);
}
cout<<ans<<endl;
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int t;
cin>>t;
while(t--)
{
cnt = 0;
memset(ma,0,sizeof(ma));
scanf("%d%d ",&m,&n);
for(int i=0;i<n;i++)
{
gets(ch[i]);
for(int j=0;j<m;j++)
if(ch[i][j]=='A'||ch[i][j]=='S')
ma[i][j] = ++cnt; //记录目标图的顶点
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(ma[i][j]) //若为外星人所在位置或者起点
bfs(i,j);
prim(); //求最短路
}
return 0;
}