AOJ - 2224 Save your cat(最小生成树)
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=45524
NY在自己的花园里养了很多猫。有一天,一个巫婆在N个点设置了魔法,然后有M条关系,每一条在两个点之间有栅栏。
NY需要损坏这些栅栏但是需要栅栏长度这么多神奇的水,因为这种水很昂贵所以希望水用的越少越好。输出最少花费。
输入N,M表示N个点,接下来N行每行一个点的坐标,接下来M行每行两个数表示x,y之间有栅栏相连。
没有栅栏会交叉,每个圈都至少有一只猫。
题目意思就是如果图产生了圈就要把一些边去掉,破坏这个圈,问需要破坏的边的最小长度。
那么每次并查集的时候只要判断在同一个连通分量那么就需要破坏掉这条边,累加即可。因为不会有重边,所以
按边的权值从大到小或者从小到大都可以。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 struct node 8 { 9 int x,y,id; 10 }; 11 struct edge 12 { 13 int u,v; 14 double cost; 15 edge() {} 16 edge(int x,int y,double z) 17 { 18 u=x; 19 v=y; 20 cost=z; 21 } 22 bool operator <(const edge& a) const 23 { 24 return cost>a.cost; 25 } 26 }; 27 28 edge es[50010]; 29 int par[10010]; 30 node p[10010]; 31 int n,m; 32 void init() 33 { 34 for(int i=1;i<=n;i++) par[i]=i; 35 } 36 37 int find(int x) 38 { 39 return x==par[x]?x:par[x]=find(par[x]); 40 } 41 42 void unite(int x,int y) 43 { 44 x=find(x); 45 y=find(y); 46 if(x!=y) par[x]=y; 47 } 48 49 double dis(int a,int b) 50 { 51 return sqrt(1.0*(p[a].x-p[b].x)*(p[a].x-p[b].x)+1.0*(p[a].y-p[b].y)*(p[a].y-p[b].y)); 52 } 53 54 double kruskal() 55 { 56 sort(es,es+m); 57 //for(int i=0;i<m;i++) printf("%d %d %lf\n",es[i].u,es[i].v,es[i].cost); 58 double s=0; 59 for(int i=0;i<m;i++) 60 { 61 edge e=es[i]; 62 if(find(e.u)!=find(e.v)) 63 { 64 unite(e.u,e.v); 65 } 66 else 67 { 68 s+=e.cost; 69 } 70 } 71 return s; 72 } 73 int main() 74 { 75 //freopen("a.txt","r",stdin); 76 int a,b; 77 double c,sum; 78 while(~scanf("%d%d",&n,&m)) 79 { 80 init(); 81 sum=0; 82 for(int i=1;i<=n;i++) 83 { 84 scanf("%d%d",&p[i].x,&p[i].y); 85 } 86 for(int i=0;i<m;i++) 87 { 88 scanf("%d%d",&a,&b); 89 c=dis(a,b); 90 es[i]=edge(a,b,c); 91 } 92 printf("%.3lf\n",kruskal()); 93 } 94 return 0; 95 }