• Codeforces 700 C. Break Up(Tarjan求桥)


    题意

    给你一个有 (n) 个点, (m) 条边的无向图,每条有边权 (w_i) ,现在要选择至多两条边断开,使得 (S, T) 不连通,并且使得边权和尽量小。

    (n le 1000, m le 30000)

    题解

    我们分要选的边数进行考虑。

    1. (0) 条边:一开始 (S,T) 不连通直接判掉即可。
    2. (1) 条边:我们发现数据较小,可以暴力做。首先这条边必定存在于 (S,T)Dfs 树的路径上,一开始先 Dfs 求出路径,然后依次枚举每条边断开,再用 Dfs 判是否连通就行了,最后把边权取个 (min) 就行了。复杂度是 (O(n(n+m)))
    3. (2) 条边:可以和上面的思路一样做,因为其中一条边也是存在于之前那条路径上的。然后我们依旧是暴力枚举第一条路径。然后我们再断开那条边,再求出 Dfs 树,然后用 Tarjan 求出桥边就行了,然后依次判断这些树边是否为桥边。如果是,那么就是一个合法解,最后把答案和这两条边权和取 (min) 。复杂度也是 (O(n(n+m))) 的。

    总结

    对于一类 (n, m) 范围不同的题,如果要暴力枚举每一条边,可以找找这条边是否有什么性质,常常可以将枚举边的条数从 (O(m)) 降到 (O(n))

    代码

    这里需要注意实现细节。比如 Dfs(S o T) 路径,我们可以不要求 (Lca) ,可以从 (S) Dfs 的时候,记下这条路径是否到达了 (T) ,因为是树所以路径唯一。

    然后会有重边的情况,我们可以第一次枚举到 (u) 点的父亲时候跳过,后面都需要更新 lowlink 就行了。

    #include <bits/stdc++.h>
    
    #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
    #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    #define Cpy(a, b) memcpy(a, b, sizeof(a))
    #define debug(x) cout << #x << ": " << x << endl
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define mp make_pair
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
    inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
    
    inline int read() {
    	int x = 0, fh = 1; char ch = getchar();
    	for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
    	for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
    	return x * fh;
    }
    
    void File() {
    #ifdef zjp_shadow
    	freopen ("F.in", "r", stdin);
    	freopen ("F.out", "w", stdout);
    #endif
    }
    
    const int N = 1010, M = 30100 << 1, inf = 0x7f7f7f7f;
    
    int Head[N], Next[M], to[M], val[M], e = 1;
    
    inline void add_edge(int u, int v) { to[++ e] = v; Next[e] = Head[u]; Head[u] = e; }
    
    inline void Add(int u, int v) { add_edge(u, v); add_edge(v, u); }
    
    #define Travel(i, u, v) for(int i = Head[u], v = to[i]; i; v = to[i = Next[i]])
    
    int S, T;
    vector<int> V, G; bitset<N> vis; bitset<M> ban;
    bool Dfs(int u) {
    	vis[u] = true; if (u == T) return true;
    	Travel(i, u, v) if (!ban[i] && !vis[v] && Dfs(v))
    		return V.push_back(i), true;
    	return false;
    }
    
    int clk, dfn[N], lowlink[N]; bitset<M> Bridge;
    void Tarjan(int u, int fa = 0) {
    	dfn[u] = lowlink[u] = ++ clk;
    	bool fir = true;
    	Travel(i, u, v) if (!ban[i]) {
    		if (v == fa && fir) { fir = false; continue ; }
    		if (!dfn[v]) {
    			Tarjan(v, u);
    			chkmin(lowlink[u], lowlink[v]);
    			if (lowlink[v] > dfn[u]) Bridge[i] = Bridge[i ^ 1] = true;
    		} else chkmin(lowlink[u], dfn[v]);
    	}
    }
    
    PII Ans;
    
    int main () {
    
    	File();
    
    	int n = read(), m = read(); S = read(); T = read();
    
    	For (i, 1, m) {
    		int u = read(), v = read(), w = read();
    		Add(u, v); val[e] = val[e ^ 1] = w;
    	}
    
    	if (!Dfs(S)) return puts("0
    0"), 0; G.swap(V);
    
    	int ans = inf;
    	for (int cur : G) {
    		ban[cur] = ban[cur ^ 1] = true; vis.reset();
    		if (!Dfs(S)) {
    			if (chkmin(ans, val[cur])) Ans = mp(cur >> 1, 0); 
    			ban[cur] = ban[cur ^ 1] = false; continue ; 
    		}
    
    		clk = 0; Bridge.reset(); Set(dfn, 0);
    		For (i, 1, n) if (!dfn[i]) Tarjan(i, 0);
    		for (int cut : V) 
    			if (Bridge[cut] && chkmin(ans, val[cur] + val[cut])) Ans = mp(cur >> 1, cut >> 1);
    
    		V.clear(); ban[cur] = ban[cur ^ 1] = false;
    	}
    	if (ans == inf) return puts("-1"), 0;
    	printf ("%d
    ", ans);
    	if (!Ans.second) printf ("1
    %d
    ", Ans.first);
    	else printf ("2
    %d %d
    ", Ans.first, Ans.second);
    
    	return 0;
    
    }
    
  • 相关阅读:
    【游学】Our trip in Baidu developer conference~
    【招新】Bit Workshop ,requiring new ~Welcome ~
    【web】Modify some style of Diandian blog
    【随谈】The little words is essence~
    【电脑】Enable administrator account in win 7
    【web】What's the hell of diandian ?Why can't recognize the videos ?
    【游学】Fortunately ,photographed with the COO of dolphin browser ,Mr.Wang,and the general mangager of Demo coffee Mr.Yan
    【电脑】Modify the default system guide in win 7
    sql中while遍历更新字段数据
    mysql报ERROR [42000]
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9556298.html
Copyright © 2020-2023  润新知