题意:有N个木桩M个栅栏,栅栏连接木桩,现在这些栅栏围成的封闭空间里有至少一只猫,要求破环若干个栅栏救出猫,问破环栅栏的最小长度。
思路:并查集,我也是参考了别人的思想,首先将边存在结构体edge里面,按照边长从大到小排序,然后遍历M条边,当加入某条边时,若两个端点的father值不同,则修改father[x],添加到同一个集合里;设想当加人某一条边时,它的两个端点的father值相同,则加入这条边将形成一个封闭空间(题目中说栅栏不会相交错),那么要打破这个封闭空间就是将这条边破环就行了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 10000+10
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
using namespace std;
struct Edge
{
int u,v;
double dis;
}edge[maxn*maxn/2];
int N,M;
int father[maxn];
double x[maxn],y[maxn];
int cmp(Edge x,Edge y)
{
return x.dis>y.dis;
}
void init(int n)
{
for (int i=1;i<=n;i++)
father[i]=i;
}
int find_father(int x)
{
if (x!=father[x])
father[x]=find_father(father[x]);
return father[x];
}
double Kruskal()
{
double s=0;
for (int i=0;i<M;i++)
{
int fu=find_father(edge[i].u);
int fv=find_father(edge[i].v);
if (fu!=fv)
{
father[fu]=fv;
s+=edge[i].dis; //不需要破环的边的长度之和
}
}
return s;
}
int main()
{
while (~scanf("%d%d",&N,&M))
{
init(N);
for (int i=1;i<=N;i++)
scanf("%lf%lf",&x[i],&y[i]);
int u,v;
double sum=0.0;
for (int i=0;i<M;i++)
{
scanf("%d%d",&u,&v);
edge[i].u=u;
edge[i].v=v;
edge[i].dis=sqrt( (x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]) );
sum+=edge[i].dis; //sum存下所有边的长度之和
}
sort(edge,edge+M,cmp);
printf("%.3f\n",sum-Kruskal());
}
return 0;
}