算法打卡:第十一章 图论part06

今日收获:冗余连接,冗余连接Ⅱ

1. 冗余连接

题目链接:108. 冗余连接

思想:新建并查集对象,判断要加入边的两个节点是否根相同。如果相同则是冗余边,不相同则加入并查集中。

方法:

java 复制代码
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        
        int N=sc.nextInt();
        DisJoint disJoint=new DisJoint(N);
        
        for (int i=0;i<N;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            
            if (disJoint.isSame(s,t)){
                System.out.println(s+" "+t);
                return;
            }
            
            disJoint.add(s,t);
        }
        
    }
}

class DisJoint{
    private int[] father;
    
    public DisJoint(int N){
        this.father=new int[N+1];
        for (int i=1;i<N+1;i++){
            father[i]=i;
        }
    }
    
    // 找寻根节点
    public int find(int node){
        return father[node]==node ? node:(father[node]=find(father[node]));
    }
    
    // 添加边
    public void add(int s,int t){
        if (isSame(s,t)){
            return;
        }
        
        father[t]=s;
    }
    
    // 是否在同一集合
    public boolean isSame(int s,int t){
        int root1=find(s);
        int root2=find(t);
        
        if (root1==root2){
            return true;
        }
        return false;
    }
}

2. 冗余连接Ⅱ

题目链接:109. 冗余连接II

思想:总共有三种不合格的情况。

(1)如果有入度为2的节点,要去掉它相连两条边的其中一条。包含两种情况:

a. 先判断去掉两者中后输入的边是否能形成有向树,如果可以形成就去掉这条边

b. 如果去掉后面输入的那条边不能形成有向树,则去掉这个节点的另外一条边

(2)如果不存在入度为2的点,则一定存在有向环。此时需要去掉形成环的最后一条输入边

方法:

java 复制代码
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        
        int N=sc.nextInt();
        // 记录节点的入度
        int[] inDegree=new int[N+1];
        
        // 记录所有的边
        List<int[]> edges=new ArrayList<>();
        for (int i=0;i<N;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            
            edges.add(new int[]{s,t});
            inDegree[t]++;
        }
        
        // 找入度为2的节点的两条边
        // 按输入的倒序添加,若有符合条件的边,删除最后输入的
        List<Integer> enough=new ArrayList<>();
        for (int i=N-1;i>=0;i--){
            if (inDegree[edges.get(i)[1]]==2){
                enough.add(i);
            }
        }
        
        // 如果存在入度为2的点
        if (enough.size()!=0){
            // 判断删除该边是否能形成有向树,如果可以的话删除该边
            if (isRemoveTree(edges,enough.get(0))){
                System.out.println(edges.get(enough.get(0))[0]+" "+edges.get(enough.get(0))[1]);
                return;
            }else {  // 删除另一条边
                System.out.println(edges.get(enough.get(1))[0]+" "+edges.get(enough.get(1))[1]);
                return;
            }
        }
        
        // 不存在入度为2的点,刚好形成一个环,把形成环的最后一条边删除
        getRemoveCircle(edges);
        
    }
    
    // 判断删除给定边是否能形成有向树
    public static boolean isRemoveTree(List<int[]> edges,int exclude){
        int N=edges.size();
        DisJoint disJoint = new DisJoint(N);
        
        for (int i=0;i<N;i++){
            if (i==exclude){  // 跳过给定边
                continue;
            }
            
            if (disJoint.isSame(edges.get(i)[0],edges.get(i)[1])){
                return false;
            }
            
            disJoint.add(edges.get(i)[0],edges.get(i)[1]);
        }
        return true;
    }
    
    
    // 删除形成有向环的最后一条边
    public static void getRemoveCircle(List<int[]> edges){
        int N=edges.size();
        DisJoint disJoint = new DisJoint(N);
        
        for (int i=0;i<N+1;i++){
            
            if (disJoint.isSame(edges.get(i)[0],edges.get(i)[1])){
                System.out.println(edges.get(i)[0]+" "+edges.get(i)[1]);
                return;
            }
            
            disJoint.add(edges.get(i)[0],edges.get(i)[1]);
        }
        return;
    }
}

class DisJoint{
    private int[] father;
    
    public DisJoint(int N){
        this.father=new int[N+1];
        for (int i=1;i<N+1;i++){
            father[i]=i;
        }
    }
    
    public int find(int node){
        return father[node]==node?node:(father[node]=find(father[node]));
    }
    
    public boolean isSame(int s,int t){
        int root1=find(s);
        int root2=find(t);
        
        if (root1==root2){
            return true;
        }
        return false;
    }
    
    public void add(int s,int t){
        if (isSame(s,t)){
            return;
        }
        
        father[s]=t;
    }
}
相关推荐
暴怒香菜统治世界2 分钟前
c语言--结构体
c语言·开发语言·数据结构·笔记·算法
大佬,咋整啊5 分钟前
C语言0基础的前端考研日记:头插法/尾插法创建单链表
c语言·数据结构·考研
WHabcwu9 分钟前
Spring Web MVC⼊⻔
java·后端·spring·mvc
coffee_baby12 分钟前
《解锁高效流程设计:深度剖析责任链模式与实战应用》
java·开发语言·责任链模式
予早12 分钟前
LeetCode 427. 建立四叉树
算法·leetcode
customer0814 分钟前
【开源免费】基于SpringBoot+Vue.JS服装销售平台(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源·intellij-idea
流星白龙16 分钟前
【C++算法】4.双指针_快乐数
c++·算法
晴子呀18 分钟前
一个有趣的编程题实战----交替打印线程
java·开发语言
羑悻的小杀马特20 分钟前
AVL树(平衡二叉树)的介绍以及相关构建
c++·算法·平衡二叉树·avl树
叶辰 .35 分钟前
POI获取模板文件,替换数据横纵动态表格、折线图、饼状图、折线饼状组合图
java