【图论】C035_LG_炸铁路(dfs 枚举桥 / 并查集)

一、Problem

A 国派出将军uim,对 B 国进行战略性措施,以解救涂炭的生灵。B 国有 nn 个城市,这些城市以铁路相连。任意两个城市都可以通过铁路直接或者间接到达。

uim 发现有些铁路被毁坏之后,某两个城市无法互相通过铁路到达。这样的铁路就被称为 key road。

uim 为了尽快使该国的物流系统瘫痪,希望炸毁铁路,以达到存在某两个城市无法互相通过铁路到达的效果。

然而,只有一发炮弹(A 国国会不给钱了)。所以,他能轰炸哪一条铁路呢?

【图论】C035_LG_炸铁路(dfs 枚举桥 / 并查集)_第1张图片

6 6
1 2
2 3
2 4
3 5
4 5
5 6

1 2
5 6

二、Solution

方法一:dfs

这本是一道 tarjan 求桥的题,但数据比较小,所以直接上暴搜了…

  • 在 dfs 之前,我们先删除一条边 id,然后去遍历图,并用 vis 标记每一个点的访问情况。
  • 遍历完成后,检查图中的所有点是否都被访问过,如果删除了边 id 还能全部访问,证明这条边 id 非所求边。

删去某一条边 id 一般的做法就是在 dfs 时:用 if 判断遍历的两个点是否是边,if (u == e[id][0] && g[u].get(i) == e[id][1])

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static class Solution {
		int n, m;
		int e[][];
		boolean[] vis;
		List<Integer>[] g;

		void dfs(int u, int id) {
			vis[u] = true;
			for (int i = 0; i < g[u].size(); i++) {
				//当前边就是 e[id],e[id][0]就是起点,e[id][1]就是终点
				if (u == e[id][0] && g[u].get(i) == e[id][1])
					continue;
				if (vis[g[u].get(i)])
					continue;
				dfs(g[u].get(i), id);
			}
		}
		void init() {
			Scanner sc = new Scanner(new BufferedInputStream(System.in));
			n = sc.nextInt(); m = sc.nextInt();
			e = new int[m+5][2];
			g = new ArrayList[2*n+5];
			for (int i = 0; i < g.length; i++)
				g[i] = new ArrayList<>();

			for (int i = 1;  i <= m; i++) {
				int a = sc.nextInt(), b = sc.nextInt();
				e[i][0] = Math.min(a, b);
				e[i][1] = Math.max(a, b);
				g[a].add(b);
				g[b].add(a);
			}
			List<int[]> res = new LinkedList<>();
			for (int i = 1; i <= m; i++) {
				vis = new boolean[n+5];
				dfs(1, i);
				for (int j = 1; j <= n; j++) {
					if (!vis[j]) {
						res.add(new int[] {e[i][0], e[i][1]});
						break;
					}
				}
			}
			Collections.sort(res, (e1, e2) -> {
			    if (e1[0] == e2[0])
			        return e1[1] - e2[1];
		        return e1[0] - e2[0];
			});
			for (int[] a : res) 
				System.out.println(a[0] + " " + a[1]);
		}
	}
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
		s.init();
    }
}

复杂度分析

  • 时间复杂度: O ( m × m ) O(m × m) O(m×m)
  • 空间复杂度: O ( n ) O(n) O(n)

方法二:并查集

合并 m-1 条边,然后每个顶点两两检查是否有公共祖先,如果有就表明这条边不是要炸的边。


复杂度分析

  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()

你可能感兴趣的:(#,图论)