《算法竞赛·快冲300题》每日一题:“最小生成树”

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。

文章目录

  • 题目描述
  • 题解
  • C++代码
  • Java代码
  • Python代码

最小生成树” ,链接: http://oj.ecustacm.cn/problem.php?id=1804

题目描述

【题目描述】
在平面中有n个点(xi,yi),两点之间的距离为欧几里得距离的平方。
求最小生成树的权重。
平面坐标满足:(0≤xi≤1000000,0≤yi≤10)
【输入格式】 输入第一行为正整数n,n不超过100000。
接下来n行,每行两个整数x和y,表示坐标点(x,y)。
【输出格式】 输出一个数表示答案。
【输入样例】

10
83 10
77 2
93 4
86 6
49 1
62 7
90 3
63 4
40 10
72 0

【输出样例】

660

题解

   本题差不多是一道最小生成树的模板题,但是需要处理好边。本题的任意两点间有边,边的总数量约为 n 2 / 2 n^2/2 n2/2,而n最大是 1 0 6 10^6 106 n 2 / 2 n^2/2 n2/2条边显然会超出空间限制。
   能否减少边的数量?注意到本题所有点的y坐标的限制是0≤yi≤10,这n个点的y坐标都在0和10之间。在平面上画11根横线;y=0,y=1,…,y=11,那么n个点都会在这11根线上。当处理到第i点时,只要把它和左边的11根线上的最近点连接,并且把它与右边的11根线上的最近点连接即可。这样得到的边,仍然会连通所有点,并且保留了最短的边。这样,每个点只需要连22个边,总边数只有22×n条。
   不过还可以简化,对每个点,只连它左边的11条边即可,不用连右边的边,请思考为什么。
   处理好边后,其他代码就是标准的最小生成树的模板。本题的边数不多,用代码比较简单的Kruskal算法编码。
【笔记】 最小生成树。

C++代码

  

#include<bits/stdc++.h>
using namespace std;
#define Mul(a) ((long long)(a) * (a))
const int N = 1e5 + 10;
typedef pair<int, int> Node;
int n, m;         //点、边
Node a[N];        //n个点的坐标
struct edge{
    int u, v;
    long long w;
}e[N * 22];           //边的数量。如果只连左边的11条边,这里改为N*11
bool cmp(edge a, edge b){ return a.w < b.w;}    //从小到大排序
void add_edge(int u, int v) {  //点u和点v连边
    m++;
    e[m].u = u;
    e[m].v = v;
    e[m].w = Mul(a[u].first - a[v].first) + Mul(a[u].second - a[v].second);
}
int s[N];//并查集
int find_set(int x){      //查询并查集,返回x的根
    if(x != s[x])
       s[x] = find_set(s[x]);     //路径压缩
    return s[x];
}
void kruskal(){
    for(int i = 1; i <= n; i++)  s[i] = i;    //并查集初始化
    sort(e + 1, e + 1 + m,cmp);               //边排序
    long long ans = 0;
    for(int i = 1; i <= m; i++){              //从小到大遍历边,加入到最小生成树
        int u = find_set(e[i].u), v = find_set(e[i].v);
        if(u==v) continue;                    //产生了圈,丢弃
        else  s[u] = v, ans += e[i].w;
    }
    cout<<ans<<endl;
}
int Last[15];
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i].first >> a[i].second;
    sort(a + 1, a + 1 + n);                    //对点排序。实际是对x从小到大排序
    //每个点往每行的左边最近点连边
    for(int i = 0; i <= 10; i++)   Last[i] = 0;
    for(int i = 1; i <= n; i++) {
        for(int y = 0; y <= 10; y++)
            if(Last[y])   add_edge(i, Last[y]);
        Last[a[i].second] = i;
    }
    //每个点往每行的右边最近点连边。可以省略
 /* for(int i = 0; i <= 10; i++)Last[i] = 0;
    for(int i = n; i >= 1; i--) {
        for(int y = 0; y <= 10; y++)
            if(Last[y])   add_edge(i, Last[y]);
        Last[a[i].second] = i;
    }*/
    kruskal();
    return 0;
}

Java代码

import java.util.*;

public class Main {
    static class Node implements Comparable<Node>{
        int x, y;
        Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int compareTo(Node o) {
            return Integer.compare(this.x, o.x);
        }
    }
    static class Edge implements Comparable<Edge>{
        int u, v;
        long w;
        Edge(int u, int v, long w) {
            this.u = u;
            this.v = v;
            this.w = w;
        }
        public int compareTo(Edge o) {
            return Long.compare(this.w, o.w);
        }
    }
    static final int N = 1_00_005;
    static Node[] a = new Node[N];
    static Edge[] e = new Edge[N * 11];
    static int[] s = new int[N];
    static int[] Last = new int[15];
    static int n, m;
    static long mul(int a) {  return (long)a * a; }

    static void addEdge(int u, int v) {
        m++;
        e[m] = new Edge(u, v, mul(a[u].x - a[v].x) + mul(a[u].y - a[v].y));
    }
    static int findSet(int x) {
        if (x != s[x])
            s[x] = findSet(s[x]);
        return s[x];
    }
    static void kruskal() {
        for (int i = 1; i <= n; i++) s[i] = i;
        Arrays.sort(e, 1, m + 1);
        long ans = 0;
        for (int i = 1; i <= m; i++) {
            int u = findSet(e[i].u), v = findSet(e[i].v);
            if (u == v) continue;
            s[u] = v;
            ans += e[i].w;
        }
        System.out.println(ans);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for (int i = 1; i <= n; i++) {
            int x = sc.nextInt(), y = sc.nextInt();
            a[i] = new Node(x, y);
        }
        Arrays.sort(a, 1, n + 1);
        for (int i = 0; i <= 10; i++) Last[i] = 0;
        for (int i = 1; i <= n; i++) {
            for (int y = 0; y <= 10; y++) 
                if (Last[y] > 0) addEdge(i, Last[y]);
            Last[a[i].y] = i;
        }
        kruskal();
    }
}

Python代码

from typing import List, Tuple
def mul(b):  return b * b
class Node:
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y
    def __lt__(self, other: "Node") -> bool:
        return self.x < other.x
class Edge:
    def __init__(self, u: int, v: int, w: int):
        self.u = u
        self.v = v
        self.w = w
    def __lt__(self, other: "Edge") -> bool:
        return self.w < other.w
N = 100005
a: List[Node] = [Node(0, 0) for i in range(N)]
e: List[Edge] = [Edge(0, 0, 0) for i in range(N * 11)]
s: List[int] = [i for i in range(N)]
Last: List[int] = [0] * 15
n = m = 0
def addEdge(u: int, v: int) -> None:
    global m
    m += 1
    e[m].u = u
    e[m].v = v
    e[m].w = mul(a[u].x - a[v].x) + mul(a[u].y - a[v].y)

def findSet(x: int) -> int:
    global s
    if x != s[x]:  s[x] = findSet(s[x])
    return s[x]

def kruskal() -> None:
    global n, m, s, e
    for i in range(1, n + 1):  s[i] = i
    e[1:] = sorted(e[1:m + 1])
    ans = 0
    for i in range(1, m + 1):
        u = findSet(e[i].u)
        v = findSet(e[i].v)
        if u == v:  continue
        s[u] = v
        ans += e[i].w
    print(ans)
if __name__ == "__main__":
    n = int(input())
    for i in range(1, n + 1):
        x, y = map(int, input().split())
        a[i] = Node(x, y)
    a[1:] = sorted(a[1:n + 1])
    Last = [0] * 15
    for i in range(1, n + 1):
        for y in range(11):
            if Last[y] > 0:  addEdge(i, Last[y])
        Last[a[i].y] = i
    kruskal()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/52555.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker存储空间报错解决(谨慎操作,会影响原来的容易镜像,不熟练切勿操作)

报错内容 [rootDream package]# docker build -t imapp . [] Building 21.0s (6/19)> [internal] load build definition from Dockerfile 0.1s> > transferring …

TCP 三次握手四次挥手浅析

大家都知道传输层中的TCP协议是面向连接的&#xff0c;提供可靠的连接服务&#xff0c;其中最出名的就是三次握手和四次挥手。 一、三次握手 三次握手的交互过程如下 喜欢钻牛角尖的我在学习三次握手的时候就想到了几个问题&#xff1a;为什么三次握手是三次&#xff1f;不是…

AnimateDiff论文解读-基于Stable Diffusion文生图模型生成动画

文章目录 1. 摘要2. 引言3. 算法3.1 Preliminaries3.2. Personalized Animation3.3 Motion Modeling Module 4. 实验5.限制6. 结论 论文&#xff1a; 《AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning》 github: https://g…

销售易和管易云接口打通对接实战

销售易和管易云接口打通对接实战 来源系统:销售易 销售易CRM支持企业从营销、销售到服务的全流程自动化业务场景&#xff0c;创新性地利用AI、大数据、物联网等新型互联网技术打造双中台型CRM&#xff1b;既能帮助B2B企业连接外部经销商、服务商、产品以及最终用户&#xff0c;…

支持多种通信方式和协议方便接入第三方服务器或云平台

2路RS485串口是一种常用的通信接口&#xff0c;可以支持Modbus Slave协议&#xff0c;并可接入SCADA、HMI、DSC、PLC等上位机。它还支持Modbus RTU Master协议&#xff0c;可用于扩展多达48个Modbus Slave设备&#xff0c;如Modbus RTU远程数据采集模块、电表、水表、柴油发电机…

【Rust学习 | 基础系列3 | Hello, Rust】编写并运行第一个Rust程序

文章目录 前言一&#xff0c;创建项目二&#xff0c;两种编译方式1. 使用rustc编译器编译2. 使用Cargo编译 总结 前言 在开始学习任何一门新的编程语言时&#xff0c;都会从编写一个简单的 “Hello, World!” 程序开始。在这一章节中&#xff0c;将会介绍如何在Rust中编写并运…

强推!大语言模型『百宝书』,一文缕清所有大模型!

夕小瑶科技说 原创 作者 | 王思若 最近&#xff0c;大型语言模型无疑是AI社区关注的焦点&#xff0c;各大科技公司和研究机构发布的大模型如同过江之鲫&#xff0c;层出不穷又眼花缭乱。 让笔者恍惚间似乎又回到了2020年国内大模型“军备竞赛”的元年&#xff0c;不过那时候…

DSA之图(4):图的应用

文章目录 0 图的应用1 生成树1.1 无向图的生成树1.2 最小生成树1.2.1 构造最小生成树1.2.2 Prim算法构造最小生成树1.2.3 Kruskal算法构造最小生成树1.2.4 两种算法的比较 1.3 最短路径1.3.1 两点间最短路径1.3.2 某源点到其他各点最短路径1.3.3 Dijkstra1.3.4 Floyd 1.4 拓扑排…

【前端知识】React 基础巩固(三十六)——RTK中的异步操作

React 基础巩固(三十六)——RTK中的异步操作 一、RTK中使用异步操作 引入RTK中的createAsyncThunk&#xff0c;在extraReducers中监听执行状态 import { createSlice, createAsyncThunk } from "reduxjs/toolkit"; import axios from "axios";export cons…

第七篇:k8s集群使用helm3安装Prometheus Operator

安装Prometheus Operator 目前网上主要有两种安装方式&#xff0c;分别为&#xff1a;1. 使用kubectl基于manifest进行安装 2. 基于helm3进行安装。第一种方式比较繁琐&#xff0c;需要手动配置yaml文件&#xff0c;特别是需要配置pvc相关内容时&#xff0c;涉及到的yaml文件太…

程序员做项目必用的工具【更新中...】

每个程序员多多少少都会有自己简化项目的小工具&#xff0c;我采访了我们公司所有的工程师总结了程序员必备工具篇。 一.unisms 官网&#xff1a;https://unisms.apistd.com/ 不会有人这年头写注册登录还是自己写验证码模块吧&#xff1f; 你该得拥有一个短信验证码平台了&…

【GUI】基于开关李雅普诺夫函数的非线性系统稳定(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

pytest 入门

1,安装pytest 打开终端或命令提示符窗口,在终端中运行以下命令来安装pytest: pip install pytestpip install -i https://pypi.tuna.tsinghua.edu.cn/simple pytest 确保您的系统上已经安装了Python。您可以在终端中运行以下命令来检查Python的安装情况: pytest --version…

汽车分析,随时间变化的燃油效率

简述 今天我们来分析一个汽车数据。 数据集由以下列组成&#xff1a; 名称&#xff1a;每辆汽车的唯一标识符。MPG&#xff1a;燃油效率&#xff0c;以英里/加仑为单位。气缸数&#xff1a;发动机中的气缸数。排量&#xff1a;发动机排量&#xff0c;表示其大小或容量。马力&…

伦敦金在非农双向挂单

对伦敦金投资有一定经验的投资者都知道&#xff0c;在非农时期&#xff0c;伦敦金市场会出现很大的波动&#xff0c;那么我们如何才能抓住这些波动呢&#xff1f;答案是很难的。但是&#xff0c;有些投资者在多年实践中发明了一种双向挂单的方法&#xff0c;这里和大家一切分享…

使用easyui的tree组件实现给角色快捷分配权限功能

这篇文章主要介绍怎么实现角色权限的快捷分配功能&#xff0c;不需要像大多数项目的授权一样&#xff0c;使用类似穿梭框的组件来授权。 具体实现&#xff1a;通过菜单树的勾选和取消勾选来给角色分配权限&#xff0c;在这之前&#xff0c;需要得到角色的菜单树&#xff0c;角色…

vue实现flv格式视频播放

公司项目需要实现摄像头实时视频播放&#xff0c;flv格式的视频。先百度使用flv.js插件实现&#xff0c;但是两个摄像头一个能放一个不能放&#xff0c;没有找到原因。&#xff08;开始两个都能放&#xff0c;后端更改地址后不有一个不能放&#xff09;但是在另一个系统上是可以…

盛元广通实验室教学仪器设备综合信息管理系统LIMS

实验室作为学生以及教师进行科研教学环境&#xff0c;对于实验室设备的使用情况、维护、借还、台账管理、盘点、报废等需要得到有效的管理&#xff0c;以促进科研教学工作的高质量开展&#xff0c;介于传统手动管理方式越发不能满足现代科研的飞速发展需要&#xff0c;实验室的…

使用Django自带的后台管理系统进行数据库管理的实例

Django自带的后台管理系统主要用来对数据库进行操作和管理。它是Django框架的一个强大功能&#xff0c;可以让你快速创建一个管理界面&#xff0c;用于管理你的应用程序的数据模型。 使用Django后台管理系统&#xff0c;你可以轻松地进行以下操作&#xff1a; 数据库管理&…

MySQL高级篇第4章(逻辑架构)

文章目录 1、逻辑架构剖析1.1 服务器处理客户端请求1.2 Connectors1.3 第一层&#xff1a;连接层1.4 第二层&#xff1a;服务层1.5 第三层&#xff1a;引擎层1.6 存储层1.7 小结 2、SQL执行流程2.1 MySQL 中的 SQL执行流程2.2 MySQL8中SQL执行原理2.3 MySQL5.7中SQL执行原理2.4…
最新文章