• HDU 4005 The war 双连通分量 缩点


    题意:

    有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值。
    求敌人在最优的情况下,使图不连通的最小费用。

    分析:

    首先求出边双连通分量,缩点成树。
    敌人如果选则树中(u,v)节点之间加一条边,则路径(u o v)中所有的边都会变成环。
    我们只能考虑删除其他的权值最小的边使图不连通。

    从敌人的角度考虑:如果使树中权值最小的边成环,那么我们的费用会增加。在最小边成环的前提下,如果还能使次小边也成环,我们的费用又会增加,以此类推。
    因此先找到最小边,然后从这条边两头DFS,肯定选择最小值所在的子树延长路径,然后用其他子树中的最小边更新答案。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int maxn = 10000 + 10;
    const int maxm = 200000 + 10;
    
    struct Edge
    {
    	int v, w, nxt;
    	Edge() {}
    	Edge(int v, int w, int nxt): v(v), w(w), nxt(nxt) {}
    };
    
    struct Graph
    {
    	int ecnt, head[maxn];
    	Edge edges[maxm];
    
    	void init() { ecnt = 0; memset(head, -1, sizeof(head)); }
    
    	void AddEdge(int u, int v, int w) {
    		edges[ecnt] = Edge(v, w, head[u]);
    		head[u] = ecnt++;
    	}
    };
    
    Graph g, t;
    
    int n, m;
    
    stack<int> S;
    int dfs_clock, pre[maxn], low[maxn];
    int scc_cnt, sccno[maxn];
    
    void dfs(int u, int fa) {
    	pre[u] = low[u] = ++dfs_clock;
    	S.push(u);
    	bool flag = false;
    	for(int i = g.head[u]; ~i; i = g.edges[i].nxt) {
    		int v = g.edges[i].v;
    		if(v == fa && !flag) { flag = true; continue; }
    		if(!pre[v]) {
    			dfs(v, u);
    			low[u] = min(low[u], low[v]);
    		} else if(!sccno[v]) low[u] = min(low[u], pre[v]);
    	}
    
    	if(low[u] == pre[u]) {
    		scc_cnt++;
    		for(;;) {
    			int x = S.top(); S.pop();
    			sccno[x] = scc_cnt;
    			if(x == u) break;
    		}
    	}
    }
    
    void find_scc() {
    	memset(pre, 0, sizeof(pre));
    	memset(sccno, 0, sizeof(sccno));
    	dfs_clock = scc_cnt = 0;
    	dfs(1, 0);
    }
    
    int ans;
    
    int dfs2(int u, int fa) {
    	int min1 = INF, min2 = INF;
    	for(int i = t.head[u]; ~i; i = t.edges[i].nxt) {
    		int v = t.edges[i].v;
    		if(v == fa) continue;
    		int tmp = t.edges[i].w;
    		tmp = min(tmp, dfs2(v, u));
    		if(tmp < min2) min2 = tmp;
    		if(min2 < min1) swap(min1, min2);
    	}
    	ans = min(ans, min2);
    	return min1;
    }
    
    int main()
    {
    	while(scanf("%d%d", &n, &m) == 2) {
    		g.init();
    		while(m--) {
    			int u, v, w; scanf("%d%d%d", &u, &v, &w);
    			g.AddEdge(u, v, w);
    			g.AddEdge(v, u, w);
    		}
    
    		find_scc();
    
    		t.init();
    		int a, b, minEdge = INF;
    		for(int u = 1; u <= n; u++) {
    			for(int i = g.head[u]; ~i; i = g.edges[i].nxt) {
    				int v = g.edges[i].v;
    				if(sccno[u] == sccno[v]) continue;
    				int w = g.edges[i].w;
    				t.AddEdge(sccno[u], sccno[v], w);
    				if(w < minEdge) { minEdge = w; a = sccno[u]; b = sccno[v]; }
    			}
    		}
    
    		ans = INF;
    		dfs2(a, b);
    		dfs2(b, a);
    		if(ans == INF) ans = -1;
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Arm宣布将在Linux中应用事务内存扩展支持
    企业上云哪种形式的云更适合?
    AT&T推出云5G网络开源工具Airship
    GitHub源码攻击事件
    你应该选择哪种树莓派?
    Electron 5.0 发布
    Redox OS 发布 0.5 版
    经典的网络安全技术
    inux下:热插拔和模块是什么
    微软宣布全新命令行+脚本工具:PowerShell 7
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5362346.html
Copyright © 2020-2023  润新知