洛谷 P2872 [USACO07DEC]Building Roads S

[USACO07DEC]Building Roads S

题目描述

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.

Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1…N) is represented by a position (Xi, Yi) on the plane (0 ≤ Xi ≤ 1,000,000; 0 ≤ Yi ≤ 1,000,000). Given the preexisting M roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.

给定 n n n 个点的坐标,第 i i i 个点的坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),这 n n n 个点编号为 1 1 1 n n n。给定 m m m 条边,第 i i i 条边连接第 u i u_i ui 个点和第 v i v_i vi 个点。现在要求你添加一些边,并且能使得任意一点都可以连通其他所有点。求添加的边的总长度的最小值。

输入格式

* Line 1: Two space-separated integers: N and M

* Lines 2…N+1: Two space-separated integers: Xi and Yi

* Lines N+2…N+M+2: Two space-separated integers: i and j, indicating that there is already a road connecting the farm i and farm j.

第一行两个整数 n , m n,m n,m 代表点数与边数。
接下来 n n n 行每行两个整数 x i , y i x_i,y_i xi,yi 代表第 i i i 个点的坐标。
接下来 m m m 行每行两个整数 u i , v i u_i,v_i ui,vi 代表第 i i i 条边连接第 u i u_i ui 个点和第 v i v_i vi 个点。

输出格式

* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.

一行一个实数代表添加的边的最小长度,要求保留两位小数,为了避免误差, 请用 64 64 64 位实型变量进行计算。

样例 #1

样例输入 #1

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

样例输出 #1

4.00

提示

数据规模与约定

对于 100 % 100\% 100% 的整数, 1 ≤ n , m ≤ 1000 1 \le n,m \le 1000 1n,m1000 1 ≤ x i , y i ≤ 1 0 6 1 \le x_i,y_i \le 10^6 1xi,yi106 1 ≤ u i , v i ≤ n 1 \le u_i,v_i \le n 1ui,vin

说明

Translated by 一只书虫仔。

思路:

由题意可知,是用最小生成树的方法。因为这道题给的是点与点之间的坐标,没有直接给出权值,所以首先可以先预处理出每个点到另外一个点的距离,然后在输入点与点之间的关系的时候将这两个点之间的距离置0。接下来的算法就和普通的最小生成树的算法一样了。
**注意:**这里的edge数组要开到 106,因为 n 最大能到 1000

代码实现:

// Kruskal 算法求最小生成树 
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
	
const int MAXN = 1e6+10; 
int fa[MAXN], cnt = 0;
struct node
{
	int u, v;
    double w;
}edge[MAXN];

struct node1
{
    int x, y;
}V[MAXN];
	
void add(int a, int b, double c)
{
    cnt++;
    edge[cnt].u = a;
    edge[cnt].v = b;
    edge[cnt].w = c;
    //cnt++;
}
bool cmp(node a, node b) 
{
	return a.w < b.w;
}
// 利用并查集的思想,将每个顶点放入一个集合中
int find(int x) 
{
	if(fa[x] == x) return x;
	fa[x] = find(fa[x]);
    return fa[x];
}
	
int main() 
{
    ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	int n, m;
    double sum = 0;
    cin >> n >> m;
    for(int i=1;i<=n;i++)
    {
        cin >> V[i].x >> V[i].y;
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            double S = sqrt((double)(V[i].x-V[j].x)*(double)(V[i].x-V[j].x)+(double)(V[i].y-V[j].y)*(double)(V[i].y-V[j].y));
            add(i, j, S);
        }
    }

    // 已连接的边之间花费设为0
    for(int i=1;i<=m;i++)
    {
        int a, b;
        cin >> a >> b;
        add(a, b, 0.0);
    }

	for(int i = 0; i <= n; i ++) 
	{
		fa[i] = i;
	}
    // 对边进行排序
	sort(edge + 1, edge + 1 + cnt, cmp);
	// 每次加入一条最短的边
	for(int i = 1; i <= cnt; i ++) 
	{
		int x = find(edge[i].u);
		int y = find(edge[i].v);
        // 如果已经在同一个集合中了,就不加入
		if(x == y) continue;
		fa[y] = x;
		sum += edge[i].w;
	}
	
	printf("%.2lf", sum);
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值