文章目录
- [108. 多余的边](#108. 多余的边)
- [109. 多余的边II](#109. 多余的边II)
108. 多余的边
无向图,直接用并查集判断是否成环就可以。
java
import java.util.Scanner;
public class Main {
private static int[] father;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int pointNum = scanner.nextInt();
father = new int[pointNum + 1];
init();
for (int i = 0; i < pointNum; i++) {
join(scanner.nextInt(), scanner.nextInt());
}
}
/**
* 并查集初始化
*/
private static void init() {
for (int i = 1; i < father.length; i++) {
// 让每个元素指向自己
father[i] = i;
}
}
/**
* 并查集寻根
*
* @param u
* @return
*/
private static int find(int u) {
// 判断 u 是否等于自己,如果是的话,直接返回自己
// 如果不等于自己,就寻找根,寻找的时候,反复进行路径压缩
return u == father[u] ? u : (father[u] = find(father[u]));
}
/**
* 判断 u 和 v 是否同根
*
* @param u
* @param v
* @return
*/
private static boolean isSame(int u, int v) {
return find(u) == find(v);
}
/**
* 添加 边 到并查集,v 指向 u
*
* @param u
* @param v
*/
private static void join(int u, int v) {
// --if-- 如果两个点已经同根,说明他们的信息已经存储到并查集中了,直接返回即可
// 寻找u的根
int uRoot = find(u);
// 寻找v的根
int vRoot = find(v);
if (uRoot == vRoot) {
// --if-- 如果u,v的根相同,说明两者已经连接了,直接输出
System.out.println(u + " " + v);
return;
}
// --if-- 将信息添加到并查集
father[vRoot] = uRoot;
}
}
109. 多余的边II
有向图,一共有三种情况,图中存在入度为2的节点,需要删除一条边,但是删除后要保证不成环,另外一种情况就是成环,没有节点入度为2。
java
import java.util.*;
class Main {
public static int N;
static DisJoint disjoint;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
disjoint = new DisJoint(N + 1);
List<Edge> edges = new ArrayList<>();
int[] indegree = new int[N + 1];
for (int i = 0; i < N; i++) {
int s = sc.nextInt();
int t = sc.nextInt();
Edge edge = new Edge(s, t);
edges.add(edge);
indegree[t]++;
}
List<Integer> vec = new ArrayList<>();
for (int i = 0; i < N; i++) {
if (indegree[edges.get(i).t] == 2) {
vec.add(i);
}
}
if (vec.size() > 0) {
if (isTreeAfterDelete(edges, vec.get(1))) {
System.out.println(edges.get(vec.get(1)).s + " " + edges.get(vec.get(1)).t);
}
else {
System.out.println(edges.get(vec.get(0)).s + " " + edges.get(vec.get(0)).t);
}
return;
}
for (int i = 0; i < N; i++) {
if (disjoint.isSame(edges.get(i).s, edges.get(i).t)) {
System.out.println(edges.get(i).s + " " + edges.get(i).t);
}
else {
disjoint.join(edges.get(i).s, edges.get(i).t);
}
}
}
public static boolean isTreeAfterDelete(List<Edge> edges, Integer v) {
disjoint = new DisJoint(N + 1);
for (int i =0; i < N; i++) {
if (i == v) {
continue;
}
if (disjoint.isSame(edges.get(i).s, edges.get(i).t)) {
return false;
}
else {
disjoint.join(edges.get(i).s, edges.get(i).t);
}
}
return true;
}
}
class Edge {
int s;
int t;
public Edge(int s, int t) {
this.s = s;
this.t = t;
}
}
class DisJoint {
private int[] father;
public DisJoint(int N) {
father = new int[N + 1];
for (int i = 0; i < N; i ++) {
father[i] = i;
}
}
public int find(int n) {
return father[n] == n ? n : (father[n] = find(father[n]));
}
public void join(int n, int m) {
n = find(n);
m = find(m);
if (n == m) {
return;
}
father[n] = m;
}
public boolean isSame(int n, int m) {
n = find(n);
m = find(m);
return n == m;
}
}