题意:一个邪恶的女巫因为嫉妒Nicholas家的猫可爱,就施了魔法让他家的猫咪困在卷子里出不来了(要不然说她邪恶呢)。现在给出她施魔法变出来的桩的坐标,栅栏i与栅栏j(是一个整体,也就是给出了一条边,边的长度是第i个桩与第j个桩间的长度)。现在让你求最少需要破坏多长的栅栏才能让可爱的猫咪都出来。
分析:若想要让猫咪出来的话,肯定是不能有环了。那么现在就有一个思想:算出全部边长总和,然后减去可以构成的最大生成树的总和(不能有环,生成树正好符合这样的条件,再加额外的边就会产生环),那么剩下的就是需要被破坏的边的总和。但是怎样求最大生成树呢?我们需要用到并查集,首先将边存在结构体里,然后按照从大到小将边长排序,接着需要遍历m条边,当加入某条边时,若两端的father[x]不同,则需要进行归并(father[x]=y),若相同的话,自然不需要加它这条边的边长了(相同的话,会构成一个封闭区间)。
注意:没有说m的范围,在开有关m的数组时,需要比n大。
以及,并查集一定要记得初始化!!!!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
struct edge{
int a1,a2;
double cost;
}G[100000];
bool cmp(edge a,edge b)
{
return a.cost>b.cost;
}
int par[10005];
int find(int x)
{
return par[x]==x?x:par[x]=find(par[x]);
}
bool unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y)return false;
par[x]=y;
return true;
}
int main()
{
int n,m,i,j,k;
cin>>n>>m;
int x[10005],y[10005];
for(i=1;i<=n;i++)
scanf("%d %d",&x[i],&y[i]);
for(i=1;i<=n;i++)par[i]=i;//初始化!!!!!
double total=0;
for(i=1;i<=m;i++){
int a,b;cin>>a>>b;double t=sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
G[i].a1=a,G[i].a2=b,G[i].cost=t;
total+=t;
}
sort(G+1,G+1+m,cmp);
int cnt=0;double len=0;
for(i=1;i<=m;i++){
if(unite(G[i].a1,G[i].a2))
cnt++,len+=G[i].cost;
if(cnt==n-1)break;
}
printf("%.3f\n",total-len);
return 0;
}