@@ -250,7 +250,105 @@ int main() {
250250## 其他语言版本
251251
252252### Java
253+ ``` java
254+ import java.util.ArrayList ;
255+ import java.util.List ;
256+ import java.util.Scanner ;
257+
258+ public class Main {
259+ static int n;
260+ static int [] father = new int [1001 ]; // 并查集数组
261+
262+ // 并查集初始化
263+ public static void init () {
264+ for (int i = 1 ; i <= n; ++ i) {
265+ father[i] = i;
266+ }
267+ }
268+
269+ // 并查集里寻根的过程
270+ public static int find (int u ) {
271+ if (u == father[u]) return u;
272+ return father[u] = find(father[u]); // 路径压缩
273+ }
274+
275+ // 将 v->u 这条边加入并查集
276+ public static void join (int u , int v ) {
277+ u = find(u);
278+ v = find(v);
279+ if (u != v) {
280+ father[v] = u; // 合并两棵树
281+ }
282+ }
253283
284+ // 判断 u 和 v 是否有同一个根
285+ public static boolean same (int u , int v ) {
286+ return find(u) == find(v);
287+ }
288+
289+ // 在有向图里找到删除的那条边,使其变成树
290+ public static void getRemoveEdge (List<int[]> edges ) {
291+ init(); // 初始化并查集
292+ for (int i = 0 ; i < n; i++ ) { // 遍历所有的边
293+ if (same(edges. get(i)[0 ], edges. get(i)[1 ])) { // 如果构成有向环了,就是要删除的边
294+ System . out. println(edges. get(i)[0 ] + " " + edges. get(i)[1 ]);
295+ return ;
296+ } else {
297+ join(edges. get(i)[0 ], edges. get(i)[1 ]);
298+ }
299+ }
300+ }
301+
302+ // 删一条边之后判断是不是树
303+ public static boolean isTreeAfterRemoveEdge (List<int[]> edges , int deleteEdge ) {
304+ init(); // 初始化并查集
305+ for (int i = 0 ; i < n; i++ ) {
306+ if (i == deleteEdge) continue ;
307+ if (same(edges. get(i)[0 ], edges. get(i)[1 ])) { // 如果构成有向环了,一定不是树
308+ return false ;
309+ }
310+ join(edges. get(i)[0 ], edges. get(i)[1 ]);
311+ }
312+ return true ;
313+ }
314+
315+ public static void main (String [] args ) {
316+ Scanner sc = new Scanner (System . in);
317+ List<int[]> edges = new ArrayList<> (); // 存储所有的边
318+
319+ n = sc. nextInt(); // 顶点数
320+ int [] inDegree = new int [n + 1 ]; // 记录每个节点的入度
321+ for (int i = 0 ; i < n; i++ ) {
322+ int s = sc. nextInt(); // 边的起点
323+ int t = sc. nextInt(); // 边的终点
324+ inDegree[t]++ ;
325+ edges. add(new int []{s, t}); // 将边加入列表
326+ }
327+
328+ List<Integer > vec = new ArrayList<> (); // 记录入度为2的边(如果有的话就两条边)
329+ // 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
330+ for (int i = n - 1 ; i >= 0 ; i-- ) {
331+ if (inDegree[edges. get(i)[1 ]] == 2 ) {
332+ vec. add(i);
333+ }
334+ }
335+
336+ // 情况一、情况二
337+ if (vec. size() > 0 ) {
338+ // vec里的边已经按照倒叙放的,所以优先删 vec.get(0) 这条边
339+ if (isTreeAfterRemoveEdge(edges, vec. get(0 ))) {
340+ System . out. println(edges. get(vec. get(0 ))[0 ] + " " + edges. get(vec. get(0 ))[1 ]);
341+ } else {
342+ System . out. println(edges. get(vec. get(1 ))[0 ] + " " + edges. get(vec. get(1 ))[1 ]);
343+ }
344+ return ;
345+ }
346+
347+ // 处理情况三:明确没有入度为2的情况,一定有有向环,找到构成环的边返回即可
348+ getRemoveEdge(edges);
349+ }
350+ }
351+ ```
254352### Python
255353
256354### Go
0 commit comments