《算法竞赛·快冲300题》每日一题:“糖果配对”

news2024/12/27 4:22:19

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

文章目录

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

糖果配对” ,链接: http://oj.ecustacm.cn/problem.php?id=1735

题目描述

【题目描述】 现在有N个小朋友,有M个不同的糖果。每个小朋友有自己最喜欢的糖果和第二喜欢的糖果。
   给定一些糖果,小朋友们会排队来领糖果,对于每个小朋友而言,如果其最喜欢的糖果还在,将会选择最喜欢的糖果,否则选择第二喜欢的糖果。
   如果二者都不在,那么这个小朋友将会哇哇大哭。
   你可以任意排列对小朋友排队的顺序,但是要保证哭的小朋友数量最小。
   请求出最小的哭泣小朋友的数量。
【输入格式】 输入格式
   输入第一行包含N和M。(N,M≤100000)
   接下来有N行,每i行包含两个数字fi和si表示第i个小朋友最喜欢和第二喜欢的糖果编号。
【输出格式】 输出一个数字表示答案。
【输入样例】

8 10
2 1
3 4
2 3
6 5
7 8
6 7
7 5
5 8

【输出样例】

1

题解

   每个孩子有最喜欢的糖果和次喜欢的糖果,从二者中选择一个,相当于一个孩子连接了两个糖果。把孩子和糖果建模为一个图,孩子是图上的边,糖果是图上的点。要求每条边和每个点进行配对,问最多有多少个点和边能够匹配?
   把样例画成下面的图,图中的边是孩子,点是孩子喜欢的糖果。例如边{1-2}是第1个孩子喜欢的糖果1、2。根据样例的数据画出2个连通子图,一个子图是{1,2,3,4},它是一棵树;一个子图是{5,6,7,8},它是一个有环图。

   容易分析得出:如果连通子图是一棵树,则匹配的数量就等于边数,或者等于点的数量减一;如果连通子图是一个有环图,匹配的数量就等于点数。例如上图中,左边子图是有3条边的树,能满足3个小朋友;右边子图是有4个点的有环图,能满足4个小朋友。
   本题经过转换后是这样一个图的连通性问题:(1)构造图;(2)查询其中有多少连通子图;(3)对每个子图,区分它是树还是有环图,分别统计边和点的数量。
   图的连通性,编码可以用BFS、DFS、并查集。下面用编码比较简单的并查集求解。
   首先读取点和边,用并查集处理,属于同一个子图的点,它们的集都相同,同时用ring标注这个集是否是有环图。
   如何用并查集处理有环图?读2个点u、v构成的边u-v时,如果发现u、v已经在以前读取和处理过,且属于一个集,说明边u-v把原来的子图变成了一个有环图。
   读取和处理完所有的点和边后,上面图示的的两个子图变成了下面的两个并查集。并查集2中包含点{1, 2, 3, 4},并查集6中包含点{5, 6, 7, 8}。

   请注意两个关键:
   (1)并查集必须用路径压缩,这样才能使得一个集中的每个点所属的集相同,例如{1, 2, 3, 4}都属于并查集2。
   (2)需要标记每个并查集是树还是有环图。下面的代码用参数ring来标记一个点是否在有环图上。只要这个并查集中有一个点的ring标记为true,这个并查集就是一个有环图。
   最后就是搜索有多少并查集,并统计每个并查集内部有多少个糖果匹配。只需用O(nlogn)的计算量即可完成这2个任务:
   (1)对所有并查集按集的大小排序,例如{1, 2, 3, 4}、{5, 6, 7, 8}这个两个并查集的点对应的集是{2, 2, 2, 2}、{6, 6, 6, 6},按集的大小排序后,同一个集的点都排在一起。排序的计算量为O(nlogn)。
   (2)从小到大遍历所有的集,如果集的大小一样,它们就属于一个集。统计这个集内部的糖果匹配数量。计算量为O(n)。
【重点】 图的连通性 。

C++代码

  

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
struct child {int s; bool ring;} c[N];         //s: 并查集;  ring:这个点是否在一个有环图上
bool cmp(struct child a, struct child b){ return a.s < b.s;}    //按s排序
int find_set(int x){                           //并查集:查询
    if(c[x].s!=x)   c[x].s=find_set(c[x].s);   //路径压缩
    return c[x].s;
}
int main(){
    int n,m;    cin>>n>>m;
    for(int i=1;i<=m;i++)  c[i].s = i,c[i], c[i].ring = false;       //并查集初始化
    for(int i=1;i<=n;i++) {
        int u,v;  cin>>u>>v;                 //读取一条边上的两个点
        u = find_set(u);                     //查询它们的集
        v = find_set(v);
        if(u==v){                //已经是同一个集,说明这个集是一个有环图
            c[u].ring = true;    //标注这个集是一个有环图
            continue;            //已经在一个集中了,不用合并
        }
        c[v].s = c[u].s;         //u、v还不在一个集中,进行并查集合并
    }
    for(int i=1;i<=m;i++)
        find_set(i);                 //利用查询进行路径压缩,使同一个集的点的所属的集相同
    sort(c+1,c+m+1,cmp);             //对集排序,让同一个集的点排在一起
    int tot = 0;                     //统计能满足多少小朋友
    for(int i=2;i<=m;i++) {          //遍历有多少个集
        bool Ring = false;           //这个集是否为有环图,初始化为非环图
        int point = 1;               //统计这个集表示的连通子图内有多少个点
        while(c[i].s == c[i-1].s) {    //如果两点的集s相同,说明它们属于同一个子图
            if(c[i-1].ring || c[i].ring )  Ring = true;  //这个集是一个有环图
            point++;                   //统计这个集合的点的数量            
i++;                       //遍历这个集
        }
        if(Ring==false) point--;      //不是有环图,是一棵树
        tot += point;
    }
    cout<<n-tot;          //不能满足的小朋友人数
    return 0;
}

Java代码

import java.util.*;
public class Main {
    static class Child {
        int s;
        boolean ring;
        public Child(int s, boolean ring) {
            this.s = s;
            this.ring = ring;
        }
    }
    static Child[] c;
    static int n, m;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        int N = 100010;
        c = new Child[N + 1];
        for (int i = 1; i <= N; i++)   c[i] = new Child(i, false);
        for (int i = 1; i <= n; i++) {
            int u = scanner.nextInt();
            int v = scanner.nextInt();
            u = findSet(u);
            v = findSet(v);
            if (u == v) {
                c[u].ring = true;
                continue;
            }
            c[v].s = c[u].s;
        }
        for (int i = 1; i <= m; i++)       findSet(i);
        Arrays.sort(c, 1, m + 1, new Comparator<Child>() {
            public int compare(Child a, Child b) { return a.s - b.s; }
        });
        int tot = 0;
        for (int i = 2; i <= m; i++) {
            boolean ring = false;
            int point = 1;
            while (c[i].s == c[i - 1].s) {
                if (c[i - 1].ring || c[i].ring)   ring = true;
                point++;
                i++;
            }
            if (!ring)   point--;
            tot += point;
        }
        System.out.println(n - tot);
    }
    static int findSet(int x) {
        if (c[x].s != x)   c[x].s = findSet(c[x].s);
        return c[x].s;
    }
}

Python代码

  

import sys
sys.setrecursionlimit(1000000)
import functools
N = 100010
class Child:
    def __init__(self, s, ring):
        self.s = s
        self.ring = ring
def cmp(a, b):   return a.s - b.s
def find_set(x):
    if c[x].s != x:  c[x].s = find_set(c[x].s)
    return c[x].s
c = []
n, m = map(int, input().split())
for i in range(N):  c.append(Child(i, False))
for i in range(1,n+1):
    u, v = map(int, input().split())
    u = find_set(u)
    v = find_set(v)
    if u == v:
        c[u].ring = True
        continue
    c[v].s = c[u].s
for i in range(1, m + 1):  find_set(i)
c[1:] = sorted(c[1:], key=functools.cmp_to_key(cmp))
tot = 0
i = 2
while i <= m:
    Ring = False
    point = 1
    while c[i].s == c[i - 1].s:
        if c[i - 1].ring or c[i].ring:  Ring = True
        point += 1
        i += 1
    if not Ring:  point -= 1
    tot += point
    i += 1
print(n - tot)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用自己的领域数据扩充baichuan模型词表(其他模型也一样)

文章目录 前言环境项目结构一、使用步骤二、训练词表三、合并词表四、效果前言 总的来说,扩充词表可以加快解码速度,对于对中文支持不太友好的模型(如llama),扩充词表还能提升模型在中文的表现。 环境 jsonlines==3.1.0 sentencepiece==0.1.99 transformers==4.28.1项目…

【Golang系统开发】搜索引擎(3) 压缩倒排索引表

写在前面 假设我们的数据集中有 800000 篇文章&#xff0c;每篇文章有 200 词条&#xff0c;每个词条有6个字符&#xff0c;倒排记录数目是 1 亿。那么如果我们倒排索引表中单单记录文档id&#xff0c;不记录文档内的频率和偏移信息。 那么 文档id 的长度就必须是 l o g 2 8…

04.Show, Attend and Tell

目录 前言泛读摘要IntroductionRelated Work小结 精读编码器&#xff1a;特征卷积解码器&#xff1a;LSTM网络随机硬注意力和确定软注意力机制硬注意力软注意力双重随机注意力 训练实验数据集评估过程定量分析定性分析 结论 代码&#xff08;略&#xff09; 前言 本课程来自深…

前端单点登录SSO面试回答

JWT鉴权机制 1.JWT用于登录身份验证 2.用户登录成功后&#xff0c;后端通过JWT机制生成一个token&#xff0c;返回给客户端 3.客户端后续的每次请求都需要携带token&#xff0c;放在header的authorization中 4.后端从authorization中拿到token后&#xff0c;通过secretKey进…

密码学学习笔记(二十):DSA签名与X.509证书

数字签名 下图是一个制作以及使用数字签名过程的通用模型。 假设Bob发送一条消息给Alice&#xff0c;尽管消息并不重要&#xff0c;也不需要保密&#xff0c;但他想让Alice知道消息确实是他本人发的。出于这个目的&#xff0c;Bob利用一个安全的散列函数&#xff0c;比如SHA-…

elaticsearch(1)

1.简介 Elasticsearch是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据。 Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引…

【C++ 记忆站】引用

文章目录 一、引用概念二、引用特性1、引用在定义时必须初始化2、一个变量可以有多个引用3、引用一旦引用一个实体&#xff0c;再不能引用其他实体 三、常引用四、使用场景1、做参数1、输出型参数2、大对象传参 2、做返回值1、传值返回2、传引用返回 五、传值、传引用效率比较六…

电脑提示msvcp140.dll丢失的解决方法,dll组件怎么处理

Windows系统有时在打开游戏或者软件时&#xff0c; 系统会弹窗提示缺少“msvcp140.dll.dll”文件 或者类似错误提示怎么办&#xff1f; 错误背景&#xff1a; msvcp140.dll是Microsoft Visual C Redistributable Package中的一个动态链接库文件&#xff0c;它在运行软件时提…

Scratch 之 算法教程 -- 递归

递归是指物体表现出相似的重复性。它在生活中很常见&#xff0c;如俄罗斯套娃、汉诺塔游戏、分形图案&#xff08;科赫雪花、谢尔宾斯三角形等&#xff09;、两个面对面的镜子、斐波那契数列&#xff0c;二叉树等 在计算机科学中&#xff0c;递归是指函数定义中重复调用自己的行…

【高频面试题】 消息中间件

文章目录 1、RabbitMQ1.1 RabbitMQ-如何保证消息不丢失1.2 RabbitMQ消息的重复消费问题如何解决的1.3 RabbitMQ中死信交换机 ? (RabbitMQ延迟队列有了解过嘛)1.4 RabbitMQ如果有100万消息堆积在MQ , 如何解决(消息堆积怎么解决)1.5 RabbitMQ的高可用机制有了解过嘛 2、Kafka2.…

【数据结构OJ题】有效的括号

原题链接&#xff1a;https://leetcode.cn/problems/valid-parentheses/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 这道题目主要考查了栈的特性&#xff1a; 题目的意思主要是要做到3点匹配&#xff1a;类型、顺序、数量。 题目给的例子是比较…

实现数字化成功:5R模式如何支持车企数字化营销

01 车企进入“大逃杀”时间 汽车行业一边是出口“捷报频传”&#xff0c;一边是内销“压力山大”。 内销的难&#xff0c;在之前中部某省的政府“骨折价”补贴掀起的“价格战”中已经可见一斑。这一颇具标志性的事件反映了汽车行业&#xff0c;尤其是燃油车行业正处在巨大的转…

uni-app 经验分享,从入门到离职(二)—— tabBar 底部导航栏实战篇

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;关于小程序 tabbar 的一些知识&#x1f3af;创建一个基本的 tabBar&#x1f4dd;最后 &#x1f4cb;前言 这篇文章的内容主题是关于小程序的 tabBar 底部导航栏的入门使用和实战技巧。通过上一篇文章的基础&#xff0c;我们…

学习笔记230801--vue项目图片绝对路径和相对路径引入编译加载问题

问题描述&#xff1a; 在组件中引入图片出现了问题,<img>标签的src属性&#xff0c;动态绑定import引入的绝对路径图片或者直接在src静态引入图片绝对路径都可以在页面渲染出来&#xff0c;在浏览器可以看到路径都转成了dataUrl&#xff0c;但是动态绑定图片的绝对路径却…

7.maven

1 初始Maven 1.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 官网&#xff1a;https://maven.apache.org/ Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&…

DHCPV6试验1:节点自动发现DHCPV6 Server,LLA地址自动配置,GUA地址配通

1、建的拓朴图如下&#xff1a; * 这里&#xff0c;我们没有配置任何DHCPV6&#xff0c;所有的都是测试自动配置的LLA地址 2、配置路由器和PC&#xff1a; 这里我们设置PC1和PC2为DHCPV6自动获取。AR路由器为全局ipv6&#xff0c;并在节点上配置ipv6 enable。 ipv6 interfa…

VB6编程IEEE浮点算法实践

纯代码实现浮点计算实际上对浮点算法的再实践。IEEE浮点表示法是Modbus RTU协议至今还在用的传送编码&#xff0c;更是WITS 1记录标准的基础。以往实现 MKI、CVI&#xff0c;MKL、CVL&#xff0c;MKS、CVS&#xff0c;MKD、CVD在高级语言里封装了现成的语句&#xff0c;现在Pow…

vue3实现扇形展示

vue3实现扇形展示 效果 html部分 <div class"box1"><div class"box"><div class"single" v-for"(item,index) in arr" :key"index":style"transform:rotate(angle[index]deg);transform-origin: 10px…

LLM应用的例子LLM use cases and tasks

您可能会认为LLMs和生成性AI主要关注聊天任务。毕竟&#xff0c;聊天机器人非常受到关注并且备受瞩目。下一个词的预测是许多不同功能背后的基本概念&#xff0c;从基本的聊天机器人开始。 但是&#xff0c;您可以使用这种概念上简单的技术执行文本生成中的其他各种任务。例如…

分布式锁实现方式

分布式锁 1 分布式锁介绍 1.1 什么是分布式 一个大型的系统往往被分为几个子系统来做&#xff0c;一个子系统可以部署在一台机器的多个 JVM(java虚拟机) 上&#xff0c;也可以部署在多台机器上。但是每一个系统不是独立的&#xff0c;不是完全独立的。需要相互通信&#xff…