1. 程式人生 > >AOJ 2224 Save your cats (Kruskal)

AOJ 2224 Save your cats (Kruskal)

one sort con -c namespace iter ott cst cin

題意:給出一個圖,去除每條邊的花費為邊的長度,求用最少的花費去除部分邊使得圖中無圈。

思路:先將所有的邊長加起來,然後減去最大生成樹,即得出最小需要破壞的籬笆長度。

#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;
}

AOJ 2224 Save your cats (Kruskal)