代码随想录Day70(图论Part06)

108.冗余连接

题目:108. 冗余连接 (kamacoder.com)

思路:每次更新输出的边,来保证删除的是输入中最后出现的那条边。关键是,我要知道哪条边可以删除,而且是在join的时候就判断

尝试(难得AC)
import java.util.Scanner;

public class Main {
    private static int[] father;
    private static int s1 =0;
    private static int t1 =0;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt(); // 节点数量

        // 初始化并查集
        father = new int[n + 1];
        init(n);


        // 读取边并构建并查集
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt();
            int t = scanner.nextInt();
            join(s, t);
        }
        System.out.println(s1+" "+t1);
        

    }

    // 并查集初始化
    private static void init(int n) {
        for (int i = 1; i <= n; i++) {
            father[i] = i;
        }
    }

    // 并查集里寻根的过程
    private static int find(int u) {
        if (u != father[u]) {
            father[u] = find(father[u]);
        }
        return father[u];
    }

    // 判断 u 和 v 是否找到同一个根
    private static boolean isSame(int u, int v) {
        return find(u) == find(v);
    }

    // 将 v -> u 这条边加入并查集
    private static void join(int u, int v) {
        int rootU = find(u);
        int rootV = find(v);
        if (rootU != rootV) {
            father[rootV] = rootU;
        }else{
            s1 = u;
            t1 = v;
        }
    }
}
小结

基于【寻找存在的路径】代码改造,如果发现输入的(s,t)指向同一个根,说明是冗余连接,通过s1,t1每次join的时候更新

109.冗余连接||

题目:109. 冗余连接II (kamacoder.com)

思路:按照题目的意思,至少有一条边是可以删除的,我想通过fa数组,找到fa中最少被指向的元素,删掉该边,或者是说,输出该边

在遍历father数组时,还需要记录是哪条边,或许可以用set来存储

尝试(标题4)
import java.util.*;

class Main {
    public static int[] father;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        
        father = new int[n + 1];
        init(n);
        
        for (int i = 0; i < n; i++) { // 修正循环范围
            int s = scanner.nextInt();
            int t = scanner.nextInt();
            join(s, t);
        }
        
        int[] count = new int[n + 1];
        Map<Integer, Integer> map = new HashMap<>(); // 使用 Map
        
        for (int i = 1; i <= n; i++) { // 修正循环范围
            int root = find(i); // 确保父节点是根节点
            count[root]++;
            map.put(i, root);
        }
        
        for (int i = 1; i <= n; i++) { // 修正循环范围
            if (count[i] == 1) {
                System.out.println(map.get(i) + " " + i);
            }
        }
    }
    
    public static void init(int n) {
        for (int i = 1; i <= n; i++) {
            father[i] = i;
        }
    }
    
    public static int find(int u) {
        if (u != father[u]) {
            father[u] = find(father[u]);
        }
        return father[u];
    }
    
    public static void join(int u, int v) {
        int rootU = find(u);
        int rootV = find(v);
        if (rootU != rootV) {
            father[rootU] = rootV;
        }
    }
}
答案
import java.util.*;

public class Main {
    public static int n;
    public static int[] father;
    public static int[] inDegree;
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        
        father = new int[n + 1];
        inDegree = new int[n + 1];
        
        List<int[]> edges = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt();
            int t = scanner.nextInt();
            inDegree[t]++;
            edges.add(new int[]{s, t});
        }
        
        List<Integer> vec = new ArrayList<>(); // 记录入度为2的边(如果有的话就两条边)
        // 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
        for (int i = n - 1; i >= 0; i--) {
            if (inDegree[edges.get(i)[1]] == 2) {
                vec.add(i);
            }
        }
        if (!vec.isEmpty()) {
            // 放在vec里的边已经按照倒序放的,所以这里就优先删vec.get(0)这条边
            if (isTreeAfterRemoveEdge(edges, vec.get(0))) {
                System.out.println(edges.get(vec.get(0))[0] + " " + edges.get(vec.get(0))[1]);
            } else {
                System.out.println(edges.get(vec.get(1))[0] + " " + edges.get(vec.get(1))[1]);
            }
            return;
        }
        
        // 处理情况三
        // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
        getRemoveEdge(edges);
    }
    
    // 并查集初始化
    public static void init() {
        for (int i = 1; i <= n; ++i) {
            father[i] = i;
        }
    }
    
    // 并查集里寻根的过程
    public static int find(int u) {
        return u == father[u] ? u : (father[u] = find(father[u]));
    }
    
    // 将v->u 这条边加入并查集
    public static void join(int u, int v) {
        u = find(u);
        v = find(v);
        if (u == v) return;
        father[v] = u;
    }
    
    // 判断 u 和 v是否找到同一个根
    public static boolean same(int u, int v) {
        u = find(u);
        v = find(v);
        return u == v;
    }
    
    // 在有向图里找到删除的那条边,使其变成树
    public static void getRemoveEdge(List<int[]> edges) {
        init(); // 初始化并查集
        for (int i = 0; i < n; i++) { // 遍历所有的边
            if (same(edges.get(i)[0], edges.get(i)[1])) { // 构成有向环了,就是要删除的边
                System.out.println(edges.get(i)[0] + " " + edges.get(i)[1]);
                return;
            } else {
                join(edges.get(i)[0], edges.get(i)[1]);
            }
        }
    }
    
    // 删一条边之后判断是不是树
    public static boolean isTreeAfterRemoveEdge(List<int[]> edges, int deleteEdge) {
        init(); // 初始化并查集
        for (int i = 0; i < n; i++) {
            if (i == deleteEdge) continue;
            if (same(edges.get(i)[0], edges.get(i)[1])) { // 构成有向环了,一定不是树
                return false;
            }
            join(edges.get(i)[0], edges.get(i)[1]);
        }
        return true;
    }
}
小结

要考虑的情况有三种

  • 有入度为2的节点
    • 删除前,先判断删除后,本图能否成为有向树
    • 删哪个都可以时,就选择顺序靠后的删除

  • 没有入度为2的节点
    • 图中有环,删掉构成环的边

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

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

相关文章

gdbserver 指南

文章目录 1. 前言2. gdbserver 远程调试2.1 准备工作2.1.1 准备 客户端 gdb 程序2.1.2 准备 服务端 gdbserver2.1.3 准备 被调试程序 2.2 调试2.2.1 通过网络远程调试2.2.1.1 通过 gdbserver 直接启动程序调试2.2.1.2 通过 gdbserver 挂接到已运行程序调试 2.2.2 通过串口远程调…

WPF对象样式

基本样式设置 Style 设置指定对象的属性 属性&#xff1a; TargetType 引用在哪个类型上面&#xff0c;例如Button、Textblock。。 如果在控件对象里面设置Style&#xff0c;则TargetType必须指定当前控件名 只在作用域里面有效果&#xff0c;其他的相同控件没有影响&…

昇思25天学习打卡营第13天|ResNet50图像分类

1. 学习内容复盘 图像分类是最基础的计算机视觉应用&#xff0c;属于有监督学习类别&#xff0c;如给定一张图像(猫、狗、飞机、汽车等等)&#xff0c;判断图像所属的类别。本章将介绍使用ResNet50网络对CIFAR-10数据集进行分类。 ResNet网络介绍 ResNet50网络是2015年由微软…

Linux应用---内存映射

写在前面&#xff1a; 在进程间通信中&#xff0c;有一种方式内存映射。内存映射也是进程间通信的方式之一&#xff0c;其效率高&#xff0c;可以直接对内存进行操作。本节我们对内存映射进行学习&#xff0c;并结合案例进行实践。 1、基本理论 内存映射&#xff1a;是将磁盘文…

ODN网络弱光聚类定界与整治

01 ODN网络弱光运维现状 ODN网络是家庭宽带连接系统-无源光网络 (PON) 的重要组成部分&#xff0c;是连接局端 OLT 和用户 ONT 之间的光路通道&#xff0c;其质量直接影响整个PON系统的性能及可靠性。ODN光纤链路包括OLT PON口、ODF、主干光纤、一级分光器、分支光纤、二级分光…

登录功能和校验

基础版 controller package com.web.management.controller;import com.web.management.pojo.Emp; import com.web.management.pojo.Result; import com.web.management.service.EmpService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.anno…

如何用Vue3和Plotly.js绘制交互式漏斗图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Plotly.js 绘制漏斗图 应用场景 漏斗图常用于可视化业务流程中的各个阶段的转换率&#xff0c;例如销售漏斗或营销漏斗。它可以帮助用户识别流程中的瓶颈和改进机会。 基本功能 本代码使用 Plotly.js 库绘制…

【微机原理及接口技术】中断控制器8259A

【微机原理及接口技术】中断控制器8259A 文章目录 【微机原理及接口技术】中断控制器8259A前言一、介绍二、8259A的内部结构和引脚三、8259A的中断工作过程四、8259A的工作方式五、8259A的编程六、外部中断服务程序总结 前言 本篇文章将就8259芯片展开介绍&#xff0c;8259A的…

【多媒体】富客户端应用程序GUI框架 JavaFX 2.0 简介

JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架&#xff0c;它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能&#xff0c;旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出&#xff0c;2011 年 10 月发布了2.0 版本。JavaFX 2.0…

OpenLayers使用

初学ol&#xff0c;实现了高德地图不同图层的切换、交互性地图飞行以及加载本地JSON数据。 说一下不同图层切换的想法&#xff1a; 1.对于标准地图和卫星地图&#xff1a;二者最初便挂载到map上&#xff0c;两个图层是叠加显示的&#xff1b;当点击按钮时&#xff0c;其实是使…

VSCode里python代码不扩展/级联了的解决办法

如图 解决办法&#xff1a;重新下载新的扩展工具 步骤如下 1、在左边工具栏打开Extensions 2、搜索框输入python&#xff0c;选择别的扩展工具&#xff0c;点击Install - 3在扩展工具所在的目录下&#xff0c;新建一个文件&#xff0c;就可以用了

指定IP地址通过远程桌面访问WINDOWS10

1:登录Windows10系统&#xff0c;在控制面板找到系统和安全&#xff0c;打开Windows Defender防火墙。 2&#xff1a;点击感觉设置。 3&#xff1a;在入站规则中&#xff0c;找到远程桌面。查看自己的网络现在是公用&#xff0c;域&#xff0c;还是专用。选择对应的网络。 4&am…

Oracle EBS PO采购订单预审批状态处理

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 采购订单状态:预审批 采购订单流程报错如下: po.plsql.PO_DOCUMENT_ACTION_AUTH.approve:90:archive_po not successful - po.plsql.PO_DOCUMENT_ACTION_PVT.do_action:110:unexpected error in acti…

js生成器,迭代器和可迭代对象详解

1.生成器函数和生成器 生成器函数是可以返回一个可迭代对象的特殊函数&#xff0c; 生成器是一个特殊的迭代器&#xff0c; 在js中可以使用function*来定义一个非连续执行的函数作为迭代算法&#xff0c; function* name() {yield value;yield value;yield value; }name: 函…

基于YOLOv5的人脸目标检测

本文是在之前的基于yolov5的人脸关键点检测项目上扩展来的。因为人脸目标检测的效果将直接影响到人脸关键点检测的效果&#xff0c;因此本文主要讲解利用yolov5训练人脸目标检测(关键点检测可以看我人脸关键点检测文章) 基于yolov5的人脸关键点检测&#xff1a;人脸关键点检测…

ROS学习笔记(18):建图与定位(2)

0.前言 上文提到现在的我们已经进入到了SLAM领域的学习&#xff0c;会涉及到大量专业知识&#xff0c;作为一个自学的大三&#xff08;好吧也快大四了&#xff09;萌新并不能保证每次文章的专业性和准确性&#xff0c;所以&#xff0c;本人推荐大家能自己去查阅一些相关书籍和…

TOB传输、承载网拓扑图

1、用户面&#xff1a;GNODEB>UPE>SPE>NPE>UPF>CMNET网 2、控制面&#xff1a;GNODEB>UPE>SPE>NPE>IP承载网>核心网

充分利用智慧校园人事系统,提升党政职务管理

智慧校园人事系统中的党政职务管理功能&#xff0c;是专为高校及教育机构设计的&#xff0c;旨在高效、精确地处理与党政职务相关的各类事务&#xff0c;包括职务任命、任期管理、职责分配、考核评估等&#xff0c;以信息化手段促进党务及行政工作的透明化、规范化。 该模块首先…

redis主从复制哨兵模式集群管理

主从复制&#xff1a; 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。缺陷&#xff1a;故障恢复无法自动化&#xff1b;写操作无法负载均衡&…

像学Excel 一样学 Pandas系列-创建数据分析维度

嗨&#xff0c;小伙伴们。又到喜闻乐见的Python 数据分析王牌库 Pandas 的学习时间。按照数据分析处理过程&#xff0c;这次轮到了新增维度的部分了。 老样子&#xff0c;我们先来回忆一下&#xff0c;一个完整数据分析的过程&#xff0c;包含哪些部分内容。 其中&#xff0c…