今日收获:冗余连接,冗余连接Ⅱ
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;
}
}