传送门:AOJ 2224
题意:有n个点和m条边,每条边有不同的权值,问最少花费多少删除边能使得图中没有圈。
思路:我们知道树是没有圈的,因此删边后的图一定是一棵树,我们想要删除的边权尽量小,就是要留下的边权尽量大,因此留下的树必定是最大生成树。
关键点就是思维的转化,剩下的就没什么难的了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define rep(i,x,n) for(int i=x;i<n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
using namespace std;
typedef pair<int,int>P;
const int MAXN=100010;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
P p[MAXN];
double Dis(P &a, P &b)
{
return sqrt((a.fi - b.fi) * (a.fi - b.fi) + (a.se - b.se) * (a.se - b.se));
}
struct node{
int u,v;
double w;
node(int _u = 0, int _v = 0, double _w = 0) : u(_u), v(_v), w(_w){
}
bool operator < (node a) const
{
return w > a.w;
}
}mp[MAXN];
int f[MAXN];
int getf(int k)
{
return k == f[k] ? k : f[k] = getf(f[k]);
}
double kruskal(int n, int m)
{
int i = 0, cnt = 1;
double sum = 0;
while(i < m && cnt < n)
{
int u = getf(mp[i].u);
int v = getf(mp[i].v);
if(u != v)
{
f[u] = v;
cnt++;
sum += mp[i].w;
}
i++;
}
return sum;
}
int main()
{
int n, m, u, v;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
scanf("%d %d", &p[i].fi, &p[i].se);
f[i] = i;
}
double sum = 0;
for(int i = 0; i < m; i++)
{
scanf("%d %d", &u, &v);
mp[i] = node(u, v, Dis(p[u], p[v]));
sum += Dis(p[u], p[v]);
}
sort(mp, mp + m);
cout << fixed << setprecision(3) << sum - kruskal(n, m) << endl;
return 0;
}