题目大意: 地图上A代表外星人, 从S出发, 吃掉所有外星人, 每吃掉外星人都可以分裂成多个(在S也可以分裂成多个)。 求最少走多少步可以吃掉所有外星人。
题目分析: 从题目可以看出S和A是等价的,把A直接认为是S即可。 问题可以转化为把所有A(S已经转化为A了)连起来需要走多少步。 最小生成树问题。 还有第二个问题就是如何求两个点之间的权重。 用bfs求两个点之间的最小距离即可。 每个点都进行一次bfs即可求得所有点对之间的最小距离。
注意: 这个题的测试样例有个很蛋疼的地方, 就是给你长宽两个数字之后, 不不仅仅是一个回车, 当时我用getchar() 读的地图, 然后用getchar()吃掉数字后面的回车符, 结果WA了···当时就懵了, 看了一遍代码实在找不出来, 就看了题解, 基本上都跟我一个思路啊,为啥我的不对, 结果看到有个题解说用getchar会wa, 然后我就试了试gets, 高版本中gets不让用, 就自己写了个gets。 就A了, 多试了几次发现, 可能是后面的数据用程序生成的, 生成的时候没有处理两个数字后面的空格。
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
typedef pair<int, int> P;
const int INF = 1 << 31 -1;
char mp[55][55];
int n, m;
int ID[55][55];
int V;
int dx[] = {0,0,-1,1}, dy[] = {1,-1,0,0};
int cost[2505][2505];
void bfs(int x, int y)
{
queue<P> que;
int cnt[55][55] = {0};
mp[x][y] = '#';
cost[ID[x][y]][ID[x][y]] = 0;
for(que.push(P(x, y)); !que.empty(); que.pop())
{
P p = que.front();
int xx = p.first;
int yy = p.second;
if(mp[xx][yy] == 'A')
cost[ID[x][y]][ID[xx][yy]] = min(cost[ID[x][y]][ID[xx][yy]], cnt[xx][yy]);
for(int i=0; i<4; ++i)
{
xx = p.first + dx[i];
yy = p.second + dy[i];
if(xx < n && yy < m && xx >= 0 && yy >= 0 && !cnt[xx][yy] && mp[xx][yy] != '#')
{
que.push(P(xx, yy));
cnt[xx][yy] = cnt[p.first][p.second] + 1;
}
}
}
mp[x][y] = 'A';
}
int mincost[2505];
int used[2505];
int Prim()
{
int ans = 0;
for(int i=0; i<V; ++i)
{
mincost[i] = INF;
used[i] = false;
}
mincost[0] = 0;
while(1)
{
int v = -1;
for(int i=0; i<V; ++i)
if(!used[i] && (v == -1 || mincost[i] < mincost[v])) v = i;
if(v == -1) break;
ans += mincost[v];
used[v] = true;
for(int i=0; i<V; ++i)
mincost[i] = min(mincost[i], cost[v][i]);
}
return ans;
}
void readline(char * s) //自制gets
{
char ch = getchar();
int i = 0;
while(ch != '\n')
{
s[i++] = ch;
ch = getchar();
}
s[i] = 0;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
V = 0;
scanf("%d%d", &m, &n);
readline(mp[0]); //吃掉多余的换行
for(int i=0; i<n; ++i)
{
readline(mp[i]);
for(int j=0; j<m; ++j)
{
if(mp[i][j] == 'A') ID[i][j] = V++;
else if(mp[i][j] == 'S')
{
ID[i][j] = V++;
mp[i][j] = 'A';
}
}
}
for(int i=0; i<V; ++i) fill(cost[i], cost[i]+V, INF);
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
if(mp[i][j] == 'A') bfs(i, j);
printf("%d\n", Prim());
}
return 0;
}