标签:save your cat aizu 2224 并查集
题意:有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; }
标签:save your cat aizu 2224 并查集
原文地址:http://blog.csdn.net/u014422052/article/details/40949149