洛谷 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.

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

输入输出格式

输入格式:

 

  • 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.

 

输出格式:

 

  • 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.

 

输入输出样例

输入样例#1:
4 1
1 1
3 1
2 3
4 3
1 4
输出样例#1:
4.00
思路:裸的最小生成树。注意精度问题。
错因:数组开小了+本题存在精度问题。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 1000000
using namespace std;
int n,m,num,tot,x[MAXN],y[MAXN],fa[MAXN],map[1010][1010];
double ans;
struct nond{
    int x,y;
    double z;
}edge[MAXN];
int cmp(nond a,nond b){
    return a.z<b.z;
}
int find(int x){
    if(fa[x]==x)    return fa[x];
    else return fa[x]=find(fa[x]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        map[u][v]=map[v][u]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(i==j)    continue;
            edge[++tot].x=i;
            edge[tot].y=j;
            double w=sqrt(double(x[i]-x[j])*double(x[i]-x[j])+double(y[i]-y[j])*double(y[i]-y[j]));
            edge[tot].z=w;
            if(map[i][j]||map[j][i])    edge[tot].z=0;
        }
    for(int i=1;i<=n;i++)    fa[i]=i;
    sort(edge+1,edge+1+tot,cmp);
    for(int i=1;i<=tot;i++){
        int dx=find(edge[i].x);
        int dy=find(edge[i].y);
        if(dx==dy)    continue;
        ans+=edge[i].z;
        num++;
        fa[dx]=dy;
        if(num==n-1)    break;
    }
    printf("%.2lf",ans);
}

 

 

转载于:https://www.cnblogs.com/cangT-Tlan/p/7416446.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个长度为 $n$ 的书架,每本书有一个高度 $h_i$。现在你可以进行以下两种操作: - 将一本书放在书架的最左边或最右边,花费为 $c_1$。 - 将一本高度为 $h_i$ 的书放在一本高度为 $h_j$ 的书的上面,花费为 $c_2$。 现在你需要将书架上的书按照高度从小到大排列,求最小花费。 输入格式 第一行包含三个整数 $n,c_1,c_2$。 第二行包含 $n$ 个整数 $h_i$。 输出格式 输出一个整数,表示最小花费。 数据范围 $1\leq n\leq 200,1\leq c_1,c_2\leq 10^9,1\leq h_i\leq 10^9$ 输入样例 5 1 2 3 1 4 2 5 输出样例 6 算法1 (动态规划) $O(n^2)$ 首先考虑一个朴素的 dp,设 $f_{i,j}$ 表示前 $i$ 本书已经排好序,第 $i+1$ 本书放在第 $j$ 个位置的最小花费。 状态转移方程为: $$ f_{i,j}=\min\{f_{i-1,k}+c_1\}+\begin{cases}&\text{if }h_{i+1}>h_j\\c_2&\text{otherwise}\end{cases} $$ 其中 $k$ 取遍 $1\sim i$,表示将第 $i+1$ 本书放在第 $k$ 个位置。 时间复杂度 $O(n^3)$ C++ 代码 算法2 (单调队列优化) $O(n^2)$ 考虑优化上述 dp,发现状态转移方程中的 $\min$ 操作可以用单调队列优化,具体来说,我们维护一个单调递增的队列 $q$,其中 $q_i$ 表示第 $i$ 个位置的最小花费,那么对于状态 $f_{i,j}$,我们只需要找到 $q$ 中第一个大于等于 $f_{i-1,k}+c_1$ 的位置 $p$,然后 $f_{i,j}=q_p+\begin{cases}&\text{if }h_{i+1}>h_j\\c_2&\text{otherwise}\end{cases}$。 时间复杂度 $O(n^2)$ C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值