题目链接:Save your cats Aizu - 2224
n个木桩,给出他们的坐标,一些木桩之间连着m个篱笆,组成了多个封闭区域,每个封闭区域里面有猫,要将猫救出来,至少拆多长的篱笆
也就是n个顶点、m条边的图,要使图中没有圈,需要去掉的边的权值至少为多少?
求图的最大生成树,总权值-生成树的总权值就是答案。
既然去掉的最小权值不好求,那就求留下的最大权值。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 10000+10;
int n, m, a, b, V, E;
struct edge
{
int u, v;
double cost;
edge() {};
edge(int a, int b, double c) {u=a; v=b; cost=c; }
bool operator<(const edge &a) const {return cost < a.cost; }
};
struct P
{
int x, y;
};
double dist(const P &a, const P &b) {return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); }
P p[MAXN];
int par[MAXN], rk[MAXN];
void init(int n)
{
for(int i=0; i<n; ++i)
{
par[i] = i;
rk[i] = 0;
}
}
int find(int x)
{
if(par[x] == x) return x;
return par[x] = find(par[x]);
}
void unite(int x, int y)
{
x = find(x);
y = find(y);
if(x==y) return;
if(rk[x] < rk[y]) par[x] = y;
else
{
par[y] = x;
if(rk[x] == rk[y]) rk[x]++;
}
}
bool same(int x, int y)
{
return find(x) == find(y);
}
int main()
{
while(scanf("%d%d", &n, &m) == 2)
{
E = 0;
edge es[m*2];
for(int i=0; i<n; ++i) scanf("%d%d", &p[i].x, &p[i].y);
double sum = 0, d;
for(int i=0; i<m; ++i)
{
scanf("%d%d", &a, &b);
--a; --b;
d = dist(p[a], p[b]);
es[E++] = edge(a, b, -d);
es[E++] = edge(b, a, -d);
sum += d;
}
sort(es, es+E);
init(n);
double ans = 0;
for(int i=0; i<E; ++i)
{
edge e = es[i];
if(!same(e.u, e.v))
{
unite(e.u, e.v);
ans += e.cost;
}
}
printf("%.5f\n", sum+ans);
}
return 0;
}