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 }
终究独木难支。