AOJ 2224 Save your cats (Kruskal)

题意:给出一个图,去除每条边的花费为边的长度,求用最少的花费去除部分边使得图中无圈。

思路:先将所有的边长加起来,然后减去最大生成树,即得出最小需要破坏的篱笆长度。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

int N, M; // 桩数量,篱笆数量
int par[10005];
void init() {
	for (int i = 1; i <= N; ++i) par[i] = i;
}
int find(int x) {
	return x == par[x] ? x : par[x] = find(par[x]);
}
bool same(int x, int y) {
	return find(x) == find(y);
}
void unite(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) par[x] = y;
}

struct point{
	int x, y;
} ps[10005];

double dist(point &p1, point &p2) {
	return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}

struct edge {
	int from, to;
	double cost;
	edge(int from, int to, double cost) : from(from), to(to), cost(cost) {}
	bool operator<(const edge &b) const { // 从大到小排序,求出最大生成树
		return cost > b.cost;
	}
};

vector<edge> es; // 边集
double ans = 0.0; // 答案

void kruskal() {
	init();
	sort(es.begin(), es.end());
	for (auto it : es) { // C++11
		if (!same(it.from, it.to)) {
			unite(it.from, it.to);
			ans -= it.cost; // 减去最大生成树的边即可
		}
	}
}

void solve() {
	kruskal();
	printf("%.3lf\n", ans);
}

int main()
{
	cin >> N >> M;
	for (int i = 1; i <= N; ++i)
		cin >> ps[i].x >> ps[i].y;
	int u, v;
	double d;
	for (int i = 0; i < M; ++i) {
		cin >> u >> v;
		d = dist(ps[u], ps[v]);
		es.push_back(edge(u, v, d));
		ans += d; // 求出所有路径和
	}
	solve();
	return 0;
}
posted @ 2017-08-20 22:22  demianzhang  阅读(275)  评论(0编辑  收藏  举报