POJ 3026
真的是一道非常好的习题
- 首先输入读取上,详见代码可以看到两处trick。一个是格式化字符串中结尾的\n,会在读取到我们所需的之后,将停留在缓存区中的空格(对于只要数字的scanf,POJ discuss处可以看到此处坑了很多人,只读入数字的scanf可以用这种技巧解决这个问题),另一个则是
%[^\n]
这种正则表达式(不完全是,姑且这么称呼)的使用 - 而是问题的转化,百思不得其解之后发现其实很简单:首先我们需要每个节点对之间最短距离,对于这种棋盘格的问题,利用bfs生成的广度优先搜索树就可以解决,在求得每个节点对之间最短距离之后,将原问题就等价转化为如何求一棵联通外星人和起点的最小生成树
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxw= 55;
const int maxn= 105;
const int INF= 0x3f3f3f3f;
int step[4][2]= {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
char mz[maxw][maxw];
vector<pair<int, int>> pts;
int n, m, tot;
int vis[maxw][maxw], dis[maxw][maxw];
int p_co[maxn], p_v[maxn], co[maxn][maxn];
void BFS(const int s)
{
memset(vis, 0, sizeof(vis));
queue<pair<int, int>> Q;
vis[pts[s].first][pts[s].second]= 1;
dis[pts[s].first][pts[s].second]= 0;
Q.push(pts[s]);
int x, y;
int v;
while (!Q.empty()){
pair<int, int> p= Q.front();
Q.pop();
v= dis[p.first][p.second];
for (int i= 0; i< 4; ++i){
x= p.first+step[i][0];
y= p.second+step[i][1];
if (x< 0 || x>= n || y< 0 || y>= m || '#'== mz[x][y] || vis[x][y]){
continue;
}
vis[x][y]= 1;
dis[x][y]= v+1;
Q.push(make_pair(x, y));
}
}
for (int i= 0; i< tot; ++i){
co[s][i]= dis[pts[i].first][pts[i].second];
}
}
int Prim()
{
for (int i= 1; i< tot; ++i){
p_co[i]= co[0][i];
p_v[i]= 0;
}
p_v[0]= 1;
p_co[0]= 0;
int ans= 0;
int minc, p;
for (int i= 1; i< tot; ++i){
minc= INF;
p= -1;
for (int j= 1; j< tot; ++j){
if (!p_v[j] && minc > p_co[j]){
minc= p_co[j];
p= j;
}
}
if (-1== p){
return -1;
}
ans+= minc;
p_v[p]= 1;
for (int j= 1; j< tot; ++j){
if (!p_v[j] && p_co[j] > co[p][j]){
p_co[j]= co[p][j];
}
}
}
return ans;
}
int main()
{
int kase;
scanf("%d", &kase);
while (kase--){
scanf("%d %d\n", &m, &n);
tot= 0;
pts.clear();
for (int i= 0; i< n; ++i){
scanf("%[^\n]\n", mz[i]);
for (int j= 0; j< m; ++j){
if ('A'== mz[i][j] || 'S'== mz[i][j]){
pts.push_back(make_pair(i, j));
++tot;
}
}
}
for (int i= 0; i< tot; ++i){
BFS(i);
}
printf("%d\n", Prim());
}
return 0;
}