luoguP2872 【[USACO07DEC]道路建设Building Roads】

该博客介绍了USACO07DEC道路建设问题,即如何通过构建最少的新道路来连接所有农场,使得所有农场都能通过已有或新建的道路互达。博客内容包括题目描述、输入输出格式、输入输出样例,以及解决该问题的思路,强调了使用最小生成树算法(如Prim或Kruskal)并考虑已存在的边,计算过程中要注意使用高精度浮点数避免精度损失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

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.

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)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。

输入输出格式

输入格式:
  • 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.

1行: 2个用空格隔开的整数:NM

2..N+1行: 第i+1行为2个用空格隔开的整数:Xi 、Yi

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

输出格式:

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.

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

输入输出样例

输入样例#1:

4 1

1

3 1

2 3

4 3

1 4

输出样例#1:

4.00

说明

题目简述:给出n个点的坐标,其中一些点已经连通,现在要把所有点连通,求修路的最小长度.

感谢@睿屿青衫丶 提供翻译

光阴似箭,日月如梭。

时间流逝,小菜鸡又可以和大家见面了。

这次,我来讲一道比较难的题(这只是我个人认为,对于daolaodaolao 来说是水题。)

先看题目:

讲的是将所有点连通,要求花费最小。

一看就是最小生成树的模板题,只是有些路已经连通了。

三下五除二,干脆利落,先打出模板再根据题目需要进行修改。

直接讲AC思路:

1.先将已有的路连通起来

2.注意建边时用勾股定理,强制转化double类型。

3.将所有点连通,要加上边的值,最后保留2位输出。

AC 代码:
#include<cstdio>//调用     scanf和printf      的库
#include<cmath>//调用     sqrt      的库
#include<algorithm>//调用     sort      的库
#include<cstdlib>//调用     exit      的库
using namespace std;
const int mx=1007;//定义mx常量
int n,m,len=0;
int f[mx];
double ans;//输出实数型
struct noda{int x,y,b;}a[mx];//点的结构体
struct nodb{noda b,e;double v;}e[mx*mx];//边的结构体
bool cmp(nodb a,nodb b) { return a.v<b.v; }//排序条件
int init()//初始化
{
    for(int i=1;i<=n;i++)f[i]=i;//一开始的老大是自己
}
int find(int x)//并查集
{
    if(f[x]==x)return x;
    else return f[x]=find(f[x]);
}
void ins()//建边,构图
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i!=j)
            {
                len++;
                e[len].b=a[i],e[len].e=a[j];
                e[len].v=sqrt((double)(a[i].x-a[j].x)*(double)(a[i].x-a[j].x)+(double)(a[i].y-a[j].y)*(double)(a[i].y-a[j].y));
                //注意勾股定理,强制转化$double$ 类型
            }
        }
    }
}
void kruskal()
{
    sort(e+1,e+len+1,cmp);//排序
    //从小到大排,取最小边
    for(int i=1;i<=len;i++)
    {
        int tx=find(e[i].b.b);
        int ty=find(e[i].e.b);
        //找各自的老大
        if(tx!=ty)ans+=e[i].v,f[tx]=ty;
        //连通,并加上边的值
    }
    printf("%.2lf",ans);//输出,保留2位小数
    exit(0);//直接结束
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y),a[i].b=i;
    //输入
    init();//初始化
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&x,&y);
        int tx=find(x);
        int ty=find(y);
        f[tx]=ty;
    }
    //连通已有的边
    ins();//建边,构图
    kruskal();//建一棵最小生成树
    return 0;
}

AC 代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值