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;
}
posted @ 2021-04-14 22:03  IdiotNe  阅读(36)  评论(0编辑  收藏  举报