BZOJ 1626 [Usaco2007 Dec]Building Roads 修建道路:kruskal(最小生成树)

时间:2022-06-19 11:04:41

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1626

题意:

  有n个农场,坐标为(x[i],y[i])。

  有m条原先就修好的路,连接农场(a[i],b[i])。

  现在要修一些路(首尾连接两个农场,长度为欧几里得距离),使得所有农场互相连通。

  问修路的最短总距离。

题解:

  最小生成树。

  提前将m对点合并,再求最小生成树。

  注:最后所有选出的边(包括原先的边)构成的并不一定是一棵树,因为原先的路中可能有环。

    所以kruskal中不用判断cnt == n-1。

AC Code:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <vector>
#define MAX_N 1005 using namespace std; struct Edge
{
int sour;
int dest;
double len;
Edge(int _sour,int _dest,double _len)
{
sour=_sour;
dest=_dest;
len=_len;
}
Edge(){}
friend bool operator < (const Edge &a,const Edge &b)
{
return a.len<b.len;
}
}; int n,m;
int x[MAX_N];
int y[MAX_N];
int par[MAX_N];
double ans;
vector<Edge> edge; void init_union_find()
{
for(int i=;i<=n;i++)
{
par[i]=i;
}
} int find(int x)
{
return par[x]==x?x:par[x]=find(par[x]);
} void unite(int x,int y)
{
int px=find(x);
int py=find(y);
if(px==py) return;
par[px]=py;
} bool same(int x,int y)
{
return find(x)==find(y);
} void read()
{
// cin>>n>>m;
scanf("%d%d",&n,&m);
init_union_find();
for(int i=;i<=n;i++)
{
// cin>>x[i]>>y[i];
scanf("%d%d",&x[i],&y[i]);
}
int a,b;
for(int i=;i<m;i++)
{
// cin>>a>>b;
scanf("%d%d",&a,&b);
unite(a,b);
}
} inline double cal_len(int a,int b)
{
long long v1=(long long)x[a]-x[b];
long long v2=(long long)y[a]-y[b];
return sqrt(v1*v1+v2*v2);
} void build_graph()
{
for(int i=;i<=n;i++)
{
for(int j=;j<i;j++)
{
edge.push_back(Edge(i,j,cal_len(i,j)));
}
}
} double kruskal()
{
sort(edge.begin(),edge.end());
double res=;
for(int i=;i<edge.size();i++)
{
Edge temp=edge[i];
if(!same(temp.sour,temp.dest))
{
res+=temp.len;
unite(temp.sour,temp.dest);
}
}
return res;
} void solve()
{
build_graph();
ans=kruskal();
} void print()
{
printf("%.2f\n",ans);
} int main()
{
read();
solve();
print();
}