[Usaco2007 Dec]Building Roads 修建道路[最小生成树]

Description

Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场)。有些农场之间原本就有道路相连。 所有N(1 <= N <= 1,000)个农场(用1..N顺次编号)在地图上都表示为坐标为(X_i, Y_i)的点(0 <= X_i <= 1,000,000;0 <= Y_i <= 1,000,000),两个农场间道路的长度自然就是代表它们的点之间的距离。现在Farmer John也告诉了你农场间原有的M(1 <= M <= 1,000)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。

Input

* 第1行: 2个用空格隔开的整数:N 和 M

* 第2..N+1行: 第i+1行为2个用空格隔开的整数:X_i、Y_i * 第N+2..N+M+2行: 每行用2个以空格隔开的整数i、j描述了一条已有的道路, 这条道路连接了农场i和农场j

Output

* 第1行: 输出使所有农场连通所需建设道路的最小总长,保留2位小数,不必做 任何额外的取整操作。为了避免精度误差,计算农场间距离及答案时 请使用64位实型变量

Sample Input

4 1
1 1
3 1
2 3
4 3
1 4

输入说明:

FJ一共有4个坐标分别为(1,1),(3,1),(2,3),(4,3)的农场。农场1和农场
4之间原本就有道路相连。

Sample Output

4.00

输出说明:

FJ选择在农场1和农场2间建一条长度为2.00的道路,在农场3和农场4间建一
条长度为2.00的道路。这样,所建道路的总长为4.00,并且这是所有方案中道路
总长最小的一种。

本来快写完的题解= = 结果win7更新的时候按到重启了QAQ 博客园没保存...想哭

算了。。再写一份好了

题解:

看到题目中的 使所有点连通并且使总值最小,就应该想到最小生成树,这个应该很容易吧?

我先把任意一个点到除它本身以外的所有点的距离(也就是边权)都求出来,把相连的两个结点之间的边权赋为0

然后就是按照裸的最小生成树写即可;

MARK一下细节:

这题最开始测试的时候WA了三个点,调试一下发现dist的值有的为 -nan0cx00000

问了一下学长,据说是因为除以0或是爆范围才会这种奇怪的值

分别断点之后发现是在求两点之间的距离的时候

double d(int x1,int y1,int x2,int y2){
 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

(x1-x2)*(x1-x2)就已经爆int了

之后把int 改成了 long long 就愉快的A了

感觉这种爆范围的地方特别要小心,上次CF的某道题mod的时候都会爆int,比较坑....

附上代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
const int maxn=1001;
int n,m;
struct node{
	int x,y;
}a[maxn];
int fa[maxn*maxn];
int x,y;
struct kru{
	int num1,num2;
	double dist;
}f[maxn*maxn];
int tot=0;
double ans=0;

bool cmp(const kru &a,const kru &b){
	return a.dist<b.dist?1:0;
}
double d(long long x1,long long y1,long long  x2,long long y2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int find(int x){
	if(fa[x]==x) return x; else return fa[x]=find(fa[x]);
}
int main(){
	freopen("roads.in","r",stdin);
	freopen("roads.out","w",stdout);
    //freopen("data.txt","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		f[++tot].num1=x;
		f[tot].num2=y;
		f[tot].dist=0;
	}
	for(int i=1;i<=n;i++)
	   for(int j=i+1;j<=n;j++){
	   	  f[++tot].num1=i;
	   	  f[tot].num2=j;
	   	  f[tot].dist=d(a[i].x,a[i].y,a[j].x,a[j].y);
	   }
	sort(f+1,f+tot+1,cmp);
	int k=0;
	for(int i=1;i<=tot;i++){
		int u=f[i].num1;
		int v=f[i].num2;
		if(find(u)!=find(v)){
			ans+=f[i].dist;
			fa[find(u)]=find(v);
			k++;
		}
		if(k==n-1) break;
	}
	printf("%.2f",ans);
	return 0;
}
时间: 2024-12-24 02:12:55

[Usaco2007 Dec]Building Roads 修建道路[最小生成树]的相关文章

bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路 -- 最小生成树

1626: [Usaco2007 Dec]Building Roads 修建道路 Time Limit: 5 Sec  Memory Limit: 64 MB Description Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场).有些农场之间原本就有道路相连. 所有N(1 <= N <= 1,000)个农场(用1..N顺次编号)在地图上都表示为坐标为(X_i,

[BZOJ1626][Usaco2007 Dec]Building Roads 修建道路

1626: [Usaco2007 Dec]Building Roads 修建道路 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1730  Solved: 727 [Submit][Status][Discuss] Description Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场).有些农场之间原本就有道路相连.

[BZOJ] 1626: [Usaco2007 Dec]Building Roads 修建道路

1626: [Usaco2007 Dec]Building Roads 修建道路 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1724  Solved: 725[Submit][Status][Discuss] Description Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场).有些农场之间原本就有道路相连. 所

BZOJ 1626: [Usaco2007 Dec]Building Roads 修建道路( MST )

计算距离时平方爆了int结果就WA了一次...... ----------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<cmath

bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路【最小生成树】

先把已有的边并查集了,然后MST即可 记得开double #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=1005; int n,m,f[N],con,tot; double x[N],y[N],ans; struct qwe { int u,v; double w; }e[N*N]; bool c

POJ 2421 Constructing Roads 修建道路 最小生成树 Kruskal算法

题目链接:POJ 2421 Constructing Roads 修建道路 Constructing Roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19698   Accepted: 8221 Description There are N villages, which are numbered from 1 to N, and you should build some roads such that e

BZOJ 1626: [Usaco2007 Dec]Building Roads

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1626 赤裸裸的最次生成树,已有的边赋为0就好了,我用了prim(因为不熟) 不过有个神坑点,算坐标中乘法会超出int范围,所以在里面也要转为double(当然不排除你一开始用的就是long long) 程序: #include<iostream> #include<cstdio> #include<cmath> #define INF 2100000000.0

bzoj1626 / P2872 [USACO07DEC]道路建设Building Roads

P2872 [USACO07DEC]道路建设Building Roads kruskal求最小生成树. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<queue> 6 #include<algorithm> 7 #define re register 8 using namespace std; 9 ty

洛谷——P2872 [USACO07DEC]道路建设Building Roads

P2872 [USACO07DEC]道路建设Building Roads 题目描述 Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms