Aizu2224-Save your cats

链接:https://vjudge.net/problem/Aizu-2224

题意:n为魔法桩的数量,m为围栏的数量,第2到n+1行为每个魔法桩的坐标,第n+2到m+1行表示两个桩之间有围栏,每个封闭的区域内都有至少一只猫,需要的圣水数量与围栏长度成正比,问救出所有猫需要破坏的围栏长度。

分析:由题意可知要去掉一些边,使得该图变成树,求这些边的最小和。我们倒过来求该图的最大生成树,事先求出所有边的权和,然后相减即可。

代码(Kruskal算法):

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 int n,m,f[11000],cnt;
 7 double ans,k;
 8 struct node
 9 {
10     int x,y;
11 }p[11000];
12 struct edge
13 {
14     int u,v;
15     double dis;
16 }e[110000];
17 bool cmp(edge a,edge b)
18 {
19     return a.dis>b.dis;
20 }
21 int find(int k)
22 {
23     if(f[k]==k)return k;
24     return f[k]=find(f[k]);
25 }
26 double powAnd(int i,int j)
27 {
28     return 1.0*((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
29 }
30 int main(void)
31 {
32     scanf("%d %d",&n,&m);
33     for(int i=1;i<=n;i++)
34     {
35         f[i]=i;
36         scanf("%d %d",&p[i].x,&p[i].y);
37     }
38     for(int i=1;i<=m;i++)
39     {
40         scanf("%d %d",&e[i].u,&e[i].v);
41         e[i].dis=sqrt(powAnd(e[i].u,e[i].v));
42         ans+=e[i].dis;
43     }
44     sort(e+1,e+1+m,cmp);
45     for(int i=1;i<=m;i++)
46     {
47         int fu=find(e[i].u),fv=find(e[i].v);
48         if(fu==fv)continue;
49         f[fu]=fv;
50         k+=e[i].dis;
51         if(++cnt==n-1)break;
52     }
53     printf("%f",ans-k);
54     return 0;
55 }

 

posted @ 2020-08-01 17:06  yanying  阅读(164)  评论(0编辑  收藏  举报