题目链接:http://poj.org/problem?id=3026
题意:
有一个迷宫,迷宫里面有一些外星人,你需要通过扫描迷宫来同化隐藏在迷宫中的外星人,迷宫里的S是起点,搜索的开始是由多个人组成的,搜索过程中,在外星人处或搜索开始的地方,该群体可能会分成两组或更多组。求同化所有外星人所需要的最小步数。
思路:
刚开始一直在纠结分组是啥意思,为嘛要分组,咋分组才能使成本最小,后来看了大佬的博客才知道这句没啥用,主要是为了把它抽象成最小生成树。
这题可以这样理解,一群外星人在一张地图当中,你有不小于外星人数量的人手,你要找到他们,并且你可以在找到外星人或出发时将人手分成任意两部分(这是不是就有点儿像最小生成树里的Prime算法)。
嗯 ,这样的话,主要问题就在于如何求两点之间的距离了,这类似于迷宫里求起点到终点的距离,因此就需要用bfs算法求迷宫里面两点之间的距离。下面可以结合代码走一遭。
噢 对,这道题里面还藏了一个自我感觉良好的坑,(据说做了这题的娃儿都被它成功坑到了,当然,我也没跑掉)输入迷宫的x,y后面还有些空格,不得不说出题人真的很淘气
My Code:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
#include<set>
using namespace std;
#define INF 1e9
typedef long long ll;
int dis[105][105],d[105],flag[105],n;
void Prime()///最小生成树
{
memset(flag,0,sizeof(flag));
for(int i =1; i <= n; i++)
d[i] = dis[1][i];
d[1] = 0;
flag[1] = 1;
int ans = 0;
for(int i = 1; i < n; i++)
{
int minn = INF,k;
for(int j = 1; j <= n; j++)
{
if(d[j] < minn && flag[j] == 0)
{
minn = d[j];
k = j;
}
}
flag[k] = 1;
ans += d[k];
for(int j = 1; j <= n; j++)
d[j] = min(d[j],dis[k][j]);
}
printf("%d\n",ans);
}
struct point
{
int x,y,step;
};
int vis[55][55],node[55][55],col,row;
///vis标记是否走过,node用来标记外星人A和起点S
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
char ch[55][55];
void bfs(int i,int j)///求出每两点之间的距离
{
memset(vis,0,sizeof(vis));
point start;
start.x = i;
start.y = j;
start.step = 0;
vis[start.x][start.y] = 1;
point cur,nxt;
queue<point> q;
q.push(start);
while(!q.empty())///遍历整个迷宫,求出起点到其他各点的距离
{
cur = q.front();
q.pop();
if(node[cur.x][cur.y]) dis[node[start.x][start.y]][node[cur.x][cur.y]] = cur.step;///碰到一个点,记录他们俩之间的距离
for(int i = 0; i < 4; i++)
{
nxt.x = cur.x + dir[i][0];
nxt.y = cur.y + dir[i][1];
nxt.step = cur.step +1;
if(nxt.x >= 0 &&nxt.x < row && nxt.y >= 0 && nxt.y < col && ch[nxt.x][nxt.y] != '#' && vis[nxt.x][nxt.y] == 0)
{
vis[nxt.x][nxt.y] = 1;
q.push(nxt);
}
}
}
return;
}
int main()
{
int t;
cin >> t;
while(t--)
{
char s[10000];
scanf("%d%d",&col,&row);
gets(s);///注意输入行列后面还有空格,确保自己代码没问题但还是wa的看看是否加了这句
memset(ch,'\0',sizeof(ch));
memset(node,0,sizeof(node));
int cunt = 1;
for(int i = 0; i < row; i++)
{
getchar();///吃掉多余的换行符
scanf("%[^\n]",ch[i]);
for(int j =0; j < col; j++)
{
if(ch[i][j] == 'S' || ch[i][j] == 'A')
node[i][j] = cunt++;
}
}
n = cunt -1;
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(node[i][j]) bfs(i,j);///以点(i,j)为起点遍历整个迷宫
}
}
Prime();
}
return 0;
}