UVA - 10397 Connect the Campus

题意:给了一张图,有n(1 ≤ n ≤ 750)个点的坐标和m条边(0 ≤ m ≤ 1000),问还要怎么建边才能让所有的点连通,把最小边长总和输出

原题链接:https://vjudge.net/problem/UVA-10397

 

其实就是一个Kruskal算法的问题,n个点两两之间的边构成边集数组,然后在已有边基础上建立最小生成树即可,这里用的是优先队列

#include
#include
#include
#include
#include
#include
using namespace std;

typedef pair PII;

struct Edge {
	int u, v;
	double w;
	
	Edge(int u, int v, double w) :u(u), v(v), w(w) {}

	bool operator > (const Edge& B) const {
		return w > B.w;
	}
};

const int Maxn = 1e3 + 10;
int fa[Maxn];
int x[Maxn];
int y[Maxn];
priority_queue, greater > pq;

int find(int p)
{
	if (p == fa[p]) return p;

	return fa[p] = find(fa[p]);
}

bool issame(int u, int v)
{
	return find(u) == find(v);
}

void unite(int u, int v)
{
	if (!issame(u, v)) fa[find(u)] = find(v);
}

void Ini()
{
	memset(fa, 0, sizeof(fa));
	memset(x, 0, sizeof(x));
	memset(y, 0, sizeof(y));
	while (!pq.empty()) pq.pop();
}

void Input(int n) 
{
	for (int i = 1; i <= n; i++)
		fa[i] = i;

	for (int i = 1; i <= n; i++)
		cin >> x[i] >> y[i];

	int m;
	cin >> m;
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		unite(u, v);
	}
}

void solve(int n)
{
	for(int i=1; i<=n ;i++)
		for (int j = i + 1; j <= n; j++) {
			int dx = x[i] - x[j];
			int dy = y[i] - y[j];
			double d = sqrt(dx * dx + dy * dy);

			pq.push(Edge(i, j, d));
		}

	double ans = 0;
	while (!pq.empty()) {
		Edge t = pq.top(); pq.pop();
		if (!issame(t.u, t.v)) {
			ans += t.w;
			unite(t.u, t.v);
		}
	}

	printf("%.2f\n", ans);
}

int main()
{
	int n;
	while (cin >> n) {
		Ini();
		Input(n);
		solve(n);
	}

	return 0;
}

  

你可能感兴趣的:(UVA - 10397 Connect the Campus)