/*
translation:
给出一张图,令这张图没有闭合区域,问最少花费多少?每消去一条边的花费是这条边的权值。
solution:
最小生成树
可以很容易证明要使得图中没有闭合区域的子图是该图的一个生成树。又要使得消去的边权值最小,
那么这个生成树肯定是最大生成树。
note:
*这道题虽然简单,但是可以总结出一个规律:即一个图的生成树必定没有环。
date:
2016.10.20
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 5;
typedef long double LD;
struct Point
{
int x, y;
Point(int x_=0, int y_=0):x(x_),y(y_){}
} p[maxn];
struct Edge
{
int u, v;
double d;
Edge(int u_=0, int v_=0, double d_=0.0):u(u_),v(v_),d(d_){}
bool operator < (const Edge& rhs) const
{
return d > rhs.d;
}
};
vector<Edge> edges;
int n, m;
int par[maxn], high[maxn];
void init()
{
for(int i = 1; i <= n; i++)
{
par[i] = i;
high[i] = 0;
}
}
int getRoot(int x)
{
return par[x] == x ? x : par[x] = getRoot(par[x]);
}
void unite(int x, int y)
{
x = getRoot(x);
y = getRoot(y);
if(x == y) return;
if(high[x] < high[y]) par[x] = y;
else
{
par[y] = x;
if(high[x] == high[y]) high[x]++;
}
}
bool same(int x, int y)
{
return getRoot(x) == getRoot(y);
}
double getDist(int i, int j)
{
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x) + (p[i].y-p[j].y)*(p[i].y-p[j].y));
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d", &n, &m))
{
edges.clear(); init();
for(int i = 1; i <= n; i++) scanf("%d%d", &p[i].x, &p[i].y);
int u, v; LD total = 0.0;
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
edges.push_back(Edge(u, v, getDist(u, v)));
total += getDist(u, v);
}
sort(edges.begin(), edges.end());
//最大生成树
int len = edges.size();
LD ans = 0.0;
for(int i = 0; i < len; i++)
{
u = edges[i].u;
v = edges[i].v;
if(!same(u, v))
{
ans += edges[i].d;
unite(u, v);
}
}
//printf("total:%llf ans:%llf\n", total, ans);
printf("%.3llf\n", total-ans);
}
return 0;
}
aoj2224(最大生成树)
最新推荐文章于 2021-10-18 16:08:56 发布