[USACO07DEC]道路建设Building Roads

题目:洛谷P2872、POJ3625。

题目大意:给你n个点的坐标,有些点已经有边连通,现在要你连上剩下的所有点,求这些边的最小长度是多少(不包括原来的边)。

解题思路:最小生成树,把所有边处理出来,跑Kruskal即可。注意原来有的边优先级最高且长度不加进答案。由于边的总数是$n^2$级别的,所以时间复杂度$O(n^2\log n^2)$。

C++ Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,fa[1005],cnt;
int b[1005][1005];
struct zb{
	int x,y;
}a[1005];
struct edge{
	int u,v;
	double l;
	int b;
	bool operator <(const edge& rhs)const{
		if(b!=rhs.b)return b>rhs.b;
		return l<rhs.l;
	}
}e[1000005];
int dad(int x){return(fa[x]==x)?(x):(fa[x]=dad(fa[x]));}
int main(){
	memset(b,0,sizeof b);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)fa[i]=i,scanf("%d%d",&a[i].x,&a[i].y);
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		b[x][y]=b[y][x]=1;
	}
	cnt=0;
	for(int i=1;i<n;++i)
	for(int j=i+1;j<=n;++j){
		e[++cnt]=(edge){i,j,sqrt((double)(a[i].x-a[j].x)*(a[i].x-a[j].x)+(double)(a[i].y-a[j].y)*(a[i].y-a[j].y)),b[i][j]};
	}
	sort(e+1,e+cnt+1);
	double ans=0;
	for(int i=1,k=0;i<=cnt&&k!=n-1;++i){
		int x=dad(e[i].u),y=dad(e[i].v);
		if(x!=y){
			fa[y]=x;
			if(!e[i].b)ans+=e[i].l;
			++k;
		}
	}
	printf("%.2f\n",ans);
	return 0;
}

 

posted @ 2017-08-23 09:02  Mrsrz  阅读(256)  评论(0编辑  收藏  举报