描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1626
给出(n)个点的坐标,其中一些点已经连通,现在要把所有点连通,求修路的最小长度.
分析
已经连好一些边的最小生成树问题.
这里顺带复习了一下Prim和Krusakal.
Prim的证明:
设当前已经连好的树为(T),当前最小的边为(e),我们来证明(e)一定在最小生成树(G)中.
假设(e)不在(G)中,则连通(G-T)和(T)的边(e')一定比(e)大(或相等).此时我们在(G)中加入(e),会形成环,去掉环中的(e'),树依然连通,而花费更小了,这与(G)是最小生成树矛盾.(如果(e)与(e')相等那么虽然花费不会更小,也就是说(e)可以不再(G)中,但是我们也可以用(e)替换(e'),换言之,(e)在(G)中是不错误的.)
所以(e)一定在最小生成树(G)中.
Kruskal的证明:
设当前连接两个不连通分量的最小的边为(e),我们来证明(e)一定在最小生成树(G)中.
假设(e)不再(G)中,则连通这两个分量的边(e')一定比(e)大(或相等).此时我们 在(G)中加入(e),会形成环,去掉环中的(e'),树依然连通,而花费更小了,这与(G)是最小生成树矛盾.(如果(e)与 (e')相等那么虽然花费不会更小,也就是说(e)可以不再(G)中,但是我们也可以用(e)替换(e'),换言之,(e)在 (G)中是不错误的.)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1000+5; 5 struct pt{ 6 double x,y; 7 pt(double x=0,double y=0):x(x),y(y){} 8 }p[maxn]; 9 struct edge{ 10 int from,to; 11 double d; 12 edge(){} 13 edge(int from,int to,double d):from(from),to(to),d(d){} 14 bool operator < (const edge &rhs) const { return d<rhs.d; } 15 }g[maxn*maxn]; 16 int n,m,cnt=1; 17 int f[maxn]; 18 double ans; 19 inline double dis(pt a,pt b){ return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); } 20 inline int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } 21 int main(){ 22 scanf("%d%d",&n,&m); 23 for(int i=1;i<=n;i++){ 24 scanf("%lf%lf",&p[i].x,&p[i].y); 25 f[i]=i; 26 } 27 for(int i=1;i<=m;i++){ 28 int u,v; scanf("%d%d",&u,&v); 29 int fu=find(u),fv=find(v); 30 if(fu!=fv) f[fu]=fv,cnt++; 31 } 32 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) g[(i-1)*n+j]=edge(i,j,dis(p[i],p[j])); 33 sort(g+1,g+1+n*n); 34 int tot=n*n; 35 for(int i=1;i<=tot,cnt<=n;i++){ 36 int fx=find(g[i].from),fy=find(g[i].to); 37 if(fx!=fy){ 38 f[fx]=fy; 39 ans+=dis(p[g[i].from],p[g[i].to]); 40 cnt++; 41 } 42 } 43 printf("%.2lf ",ans); 44 return 0; 45 }