蓝桥杯第793题——排水系统

news2024/10/7 10:24:54

题目描述

对于一个城市来说,排水系统是极其重要的一个部分。

有一天,小 C 拿到了某座城市排水系统的设计图。排水系统由 n 个排水结点(它们从 1∼n 编号)和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水结点的污水(简称为该结点的汇集管道),也有若干个管道向其他的排水结点排出污水(简称为该结点的排出管道)。

排水系统的结点中有 m 个污水接收口,它们的编号分别为 1,2,…,m,污水只能从这些接收口流入排水系统,并且这些结点没有汇集管道。排水系统中还有若干个最终排水口,它们将污水运送到污水处理厂,没有排出管道的结点便可视为一个最终排水口。

现在各个污水接收口分别都接收了 1 吨污水,污水进入每个结点后,会均等地从当前结点的每一个排出管道流向其他排水结点,而最终排水口将把污水排出系统。

现在小 C 想知道,在该城市的排水系统中,每个最终排水口会排出多少污水。该城市的排水系统设计科学,管道不会形成回路,即不会发生污水形成环流的情况。

输入描述

第一行两个用单个空格分隔的整数 n,m。分别表示排水结点数与接收口数量。

接下来 n 行,第 i 行用于描述结点 i 的所有排出管道。其中每行第一个整数 di​ 表示其排出管道的数量,接下来 di​个用单个空格分隔的整数 a1​,a2​,…,adi​​ 依次表示管道的目标排水结点。 保证不会出现两条起始结点与目标结点均相同的管道。

其中,1 ≤ n ≤ 10^5,1 ≤ m ≤ 10,0 ≤ di ​≤ 5。

数据保证,污水在从一个接收口流向一个最终排水口的过程中,不会经过超过 1010 个中间排水结点(即接收口和最终排水口不算在内)。

输出描述

输出若干行,按照编号从小到大的顺序,给出每个最终排水口排出的污水体积。其中体积使用分数形式进行输出,即每行输出两个用单个空格分隔的整数 p,q,表示排出的污水体积为 \frac{p}{q}​ 。要求 p 与 q 互素,q=1 时也需要输出 q。

输入输出样例

示例 1

输入

5 1
3 2 3 5
2 4 5
2 5 4
0
0

输出

1 3
2 3

 解题思路

本题是有向无环图的拓扑排序,而拓扑排序其实就是在图上的搜索,本质上就是dfs和bfs。

这题是典型的有起点有终点的有向图,我们自然而然的想到使用bfs进行遍历,一般像这样的题我们有以下需要关注的点:

  1. 使用邻接表存储点很多的稀疏图;使用ru和chu两个长度为n的数组记录每个点的入度和出度;使用链式队列完成bfs等。
  2. 通常我们可以开辟dp数组记录节点状态,但是本题比较特殊,对于每个点的状态使用p和q组合的一个分数来表示,这样我们就可以利用p和q数组代替dp数组记录节点状态了。

这道题需要我们对分数除法、分数加法、分数约分的过程进行模拟,其内容笔者使用了一个addWater方法进行操作,调用了最大公约数gcd和最小公倍数lcm算法,属于算法有关基础数学知识的内容。

这里需要注意的是,由于分数可能很大,所以我们不仅需要使用long类型进行存储计算,还要对求最小公倍数的时候先除以最大公因数再乘第二个数,否则有可能溢出。

代码题解

具体的代码并没有难以理解的地方,以下是具体的代码:

import java.io.*;
import java.util.*;

public class Main {

    static int n, m;
    static ArrayList<ArrayList<Integer>> edges;
    static int[] ru, chu;
    static long[] p, q;
    static Queue<Integer> qu;
    
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        String[] temp = in.readLine().split(" ");
        n = Integer.parseInt(temp[0]);
        m = Integer.parseInt(temp[1]);
        init();
        for (int i = 1; i <= n; i++) {
            temp = in.readLine().split(" ");
            int t = Integer.parseInt(temp[0]);
            chu[i] = t;
            for (int j = 1; j <= t; j++) {
                int next = Integer.parseInt(temp[j]);
                edges.get(i).add(next);
                ru[next]++;
            }
        }
        for (int i = 1; i <= m; i++) {
            qu.add(i);
            p[i] = 1;
            q[i] = 1;
        }
        while (!qu.isEmpty()) {
            int t = qu.poll();
            for (int e : edges.get(t)) {
                addWater(t, e, chu[t]);
                ru[e]--;
                if (ru[e] == 0 && chu[e] > 0) {
                    qu.add(e);
                }
            }
            p[t] = 0;
            q[t] = 0;
        }
        for (int i = 1; i <= n; i++) {
            if (p[i] != 0) {
                out.print(p[i]);
                out.print(" ");
                out.print(q[i]);
                out.print("\n");
            }
        }
        out.flush();
    }
    public static void addWater(int sourse, int target, int num) {
        long p1 = p[sourse];
        long q1 = q[sourse];
        long t = gcd(p1, num);
        p1 /= t;
        q1 *= num / t;
        
        long p2 = p[target];
        long q2 = q[target];
        if (p2 == 0) {
            p[target] = p1;
            q[target] = q1;
        } else {
            long x = lcm(q1,  q2);
            long t1 = x / q1 * p1 + x / q2 * p2;
            long t2 = x;
            long tt = gcd(t1, t2);
            p[target] = t1 / tt;
            q[target] = t2 / tt;
        }
    }
    public static long gcd(long a, long b) {
        return a % b == 0 ? b : gcd(b, a % b);
    }
    public static long lcm(long a, long b) {
    	return a / gcd(a, b) * b;
    }
    public static void init() {
        edges = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            edges.add(new ArrayList<>());
        }
        p = new long[n + 1];
        q = new long[n + 1];
        ru = new int[n + 1];
        chu = new int[n + 1];
        qu = new LinkedList<>();
    }
}

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

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

相关文章

SSM框架学习——工厂模式、Spring核心容器与Bean

工厂模式、核心容器与Spring Bean 工厂模式 工厂模式是Java中常用的一种设计模式&#xff0c;这种类型的设计模式属于创建型模式。说白了在代码层面就是取消了new的使用。 工厂模式有三种&#xff1a; 简单工厂模式工厂方法模式抽象工厂模式 举个例子&#xff0c;我们去买…

Ubuntu20.04安装MatlabR2018a

一、安装包 安装包下载链接 提取码&#xff1a;kve2 网上相关教程很多&#xff0c;此处仅作为安装软件记录&#xff0c;方便后续软件重装&#xff0c;大家按需取用。 二、安装 1. 相关文件一览 下载并解压文件后&#xff0c;如下图所示&#xff1a; 2. 挂载镜像并安装 2…

C++11---右值引用(深度讲解)

简要介绍 右值引用是C11的新特性,无论左值引用还是右值引用&#xff0c;都是在给对象取别名 什么是左值 什么是右值 1.左值,左值引用 左值是一个数据的表达式(例如变量或者解引用后的指针),我们可以对其进行取地址和修改赋值,左值可以出现在赋值符号的左边,而右值不能出现在…

深度解析C语言——预处理详解

对C语言有一定了解的同学&#xff0c;相信对预处理一定不会陌生。今天我们就来聊一聊一些预处理的相关知识。预处理是在编译之前对源文件进行简单加工的过程&#xff0c;主要是处理以#开头的命令&#xff0c;例如#include <stdio.h>、#define等。预处理是C语言的一个重要…

leetcode721. 合并账户【两种方法;并查集;dfs】

文章目录 并查集&#xff08;方法一&#xff09;dfs&#xff08;方法二&#xff09;dfs换一种写法 并查集&#xff08;方法一&#xff09; class Solution {unordered_map<string, int> index; // 每个邮箱都有一个唯一编号int root[10010]; // 并查集…

C++算法——滑动窗口

一、长度最小的子数组 1.链接 209. 长度最小的子数组 - 力扣&#xff08;LeetCode&#xff09; 2.描述 3.思路 本题从暴力求解的方式去切入&#xff0c;逐步优化成“滑动窗口”&#xff0c;首先&#xff0c;暴力枚举出各种组合的话&#xff0c;我们先让一个指针指向第一个&…

手机销量分析案例

项目背景 某电商商城随着业务量的发展&#xff0c;积累了大量的用户手机销售订单数据。决策层希望能够通过对这些数据的分析了解更多的用户信息及用户的分布&#xff0c;从而可以指导下一年的市场营销方案以及更加精准的定位市场&#xff0c;进行广告投放。 数据说明 数据时…

JAVA基础02-Java语言基础以及编译准备工作

什么是JAVA语言 Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用的两个特征。 &#xff08;可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式…

洛谷P1000超级玛丽游戏题解[Python, Rust, Go]

题目 打印超级玛丽字符图像 小技巧 直接复制题目的超级玛丽符号首行会有空格问题&#xff0c;一直AC不过&#xff0c;一行一行地复制就OK了&#x1f44c;。 Rust 题解 fn main() {println!(" ********************####....#.#..###.....##....###...…

什么是 Nginx?(一)

前段时间在网上看到一个有意思的话题&#xff1a;只知道 Nginx 牛逼&#xff0c;却不知道它怎么支持百万并发&#xff1f; 无论是运维、开发、测试&#xff0c;Nginx 技术栈的学习总是必不可少的&#xff0c;只是不同的岗位掌握的深度与广度不同而已。 Nginx 是开源、高性能、…

MATLAB科研绘图与学术图表绘制从入门到精通

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

算法学习——LeetCode力扣图论篇1(797. 所有可能的路径、200. 岛屿数量、695. 岛屿的最大面积)

算法学习——LeetCode力扣图论篇1 797. 所有可能的路径 797. 所有可能的路径 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个有 n 个节点的 有向无环图&#xff08;DAG&#xff09;&#xff0c;请你找出所有从节点 0 到节点 n-1 的路径并输出&#xff08;不要求按特…

golang语言系列:Web框架+路由 之 Gin

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是golang语言学习系列&#xff0c;本篇对Gin框架的基本使用方法进行学习 1.Gin框架是什么 Gin 是一个 Go (Golang) 编写的轻量级 http web 框架&#xff0c;运行速度非常快&#xff0c;如果你是性能和高效的追求者…

java项目基于Springboot和Vue的高校心理教育辅导系统的设计与实现

今天要和大家聊的是基于Springboot和Vue的高校心理教育辅导系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&…

C++完美转发(适合小白)

我们知道&#xff0c;C中有左值引用和右值引用&#xff0c;首先我们要知道什么是左值什么是右值。 左值&#xff1a;表达式结束后依然存在的持久对象。左值可以出现在赋值语句的左边或右边。例如&#xff0c;变量和函数返回的引用都是左值。左值通常有持久的地址&#xff0c;可…

Python深度学习034:cuda的环境如何配置

文章目录 1.安装nvidia cuda驱动CMD中看一下cuda版本:下载并安装cuda驱动2.创建虚拟环境并安装pytorch的torch_cuda3.测试附录1.安装nvidia cuda驱动 CMD中看一下cuda版本: 注意: 红框的cuda版本,是你的显卡能装的最高的cuda版本,所以可以选择低于它的版本。比如我的是11…

Go项目结构整洁实现|GitHub 3.5k

一、前言 hi&#xff0c;大家好&#xff0c;这里是白泽。今天给大家分享一个GitHub &#x1f31f; 3.5k 的 Go项目&#xff1a;go-backend-clean-arch https://github.com/amitshekhariitbhu/go-backend-clean-architecture 这个项目是一位老外写的&#xff0c;通过一个 HTT…

HTML基本元素

文章目录 如何制作标题如何制作文字如何做粗体字检查我们程序码给输出文字添加属性 HTML 一个HTML标签包含着&#xff1a; 起始标签&#xff1a;它包含了元素的名字&#xff0c;夹在一对 <、>&#xff08;尖括号&#xff09;之间。它指明元素从何处开始生效。结束标签&am…

《Git版本控制管理》笔记

第三章 git --version查看版本号git --help查看帮助文档裸双破折号分离参数 git diff -w master origin – tools/Makefile将当前目录或任何目录转化为Git版本库 git init 初始化之后项目目录中&#xff0c;有名为.git的文件git status 查看git状态git commit 提供日志消息和作…

整型之韵,数之舞:大小端与浮点数的内存之旅

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱’博客 所属栏目&#xff1a;人工智能 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 1.0 整形提升 我们先来看看代码。 int main() {char a 3;char b 127;char …