zoukankan      html  css  js  c++  java
  • 「POJ 3177」Redundant Paths G

    为了从 $F$ 个草场中的一个走到另一个,贝茜和她的同伴们不得不路过一些她们讨厌的可怕的树。奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择。

    每对草场之间已经有至少一条路径,给出所有 $R$ 条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量。

    路径由若干道路首尾相连而成,两条路径相互分离,是指两条路径没有一条重合的道路,但是两条分离的路径上可以有一些相同的草场。

    对于同一对草场之间,可能已经有两条不同的道路,你也可以在它们之间再建一条道路,作为另一条不同的道路。

    链接

    LOJ 10098

    Luogu 2860

    POJ 3177

    题解

    在一个边双连通图里的点之间的连边是不会减少桥的数目的。缩点后得到的图必然是一棵树,在这棵树中,如果每两个叶子节点连上一条边,就可以用最少的边使树达到边双连通。

    具体步骤:

    1. 先用 Tarjan 求边双连通分量,并缩点;

    2. 计算缩点后每个点边的数目,如果为 1,则是叶子节点;

    3. 统计叶子节点数目,$ m{ans}=(leaf+1) div 2$。

    因为是双向建边,故需要一个 $mathrm{vis}$ 值记录方向边是否被访问。

    代码

    vis[i] 记录序号为 $i$ 的边是否被访问过。

    i & 1 ? (i + 1) : (i - 1) 表示与序号为 $i$ 的边方向相反的边,由建边方式所决定。

    注意:在 tarjan 函数中,vis 初始值为零,故当值为零时,表示未访问;当求叶子数目时,vis 值非零,故当值为非零时,表示未访问。

    #include <cstdio>
    
    const int vSIZE = 100005;
    const int eSIZE = 400005;
    
    int line[vSIZE];
    int bcc[vSIZE], bccTot, vis[vSIZE];
    int st[vSIZE], top;
    int low[vSIZE], dfn[vSIZE], time;
    int h[eSIZE], to[eSIZE], nxt[eSIZE], tot;
    
    int min(int x, int y) {
    	return x < y ? x : y;
    }
    
    void add(int x, int y) {
    	to[++tot] = y;
    	nxt[tot] = h[x];
    	h[x] = tot;
    }
    
    void tarjan(int x) {
    	low[x] = dfn[x] = ++time;
    	st[++top] = x;
    	for (int i = h[x]; i; i = nxt[i]) {
    		if (!vis[i & 1 ? (i + 1) : (i - 1)]){
    			vis[i] = 1;
    			int y = to[i];
    			if (!dfn[y]) {
    				tarjan(y);
    				low[x] = min(low[x], low[y]);
    			} else {
    				low[x] = min(low[x], dfn[y]);
    			}
    		}
    		vis[i] = 1;
    	}
    	if (low[x] >= dfn[x]) {
    		bcc[x] = ++bccTot;
    		while (st[top] != x) {
    			bcc[st[top--]] = bccTot;
    		}
    		top--;
    	}
    }
    
    int main() {
    	int n, m, ans = 0, leaf = 0;
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		int x, y;
    		scanf("%d %d", &x, &y);
    		add(x, y);
    		add(y, x);
    	}
    	for (int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    
    	for (int i = 1; i <= n; i++) {
    		for (int j = h[i]; j; j = nxt[j]) {
    			if (vis[j & 1 ? (j + 1) : (j - 1)]){
    				if (bcc[i] != bcc[to[j]]) {
    					line[bcc[i]]++;
    					line[bcc[to[j]]]++;
    				}
    			}
    			vis[j] = 0;
    		}
    	}
    
    	for (int i = 1; i <= bccTot; i++) if (line[i] == 1) leaf++;
    	ans = (leaf + 1) >> 1;
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Tree 点分治
    [LUOGU4149][IOI2011]Race
    [BZOJ2152] 聪聪可可
    [LUOGU3413] SAC#1
    [JZOJ5776]【NOIP2008模拟】小x游世界树
    [JZOJ5775]【NOIP2008模拟】农夫约的假期
    [JZOJ5781]【NOIP提高A组模拟2018.8.8】秘密通道
    [JZOJ5778]【NOIP提高A组模拟2018.8.8】没有硝烟的战争
    [JZOJ5773]【NOIP2008模拟】简单数学题
    [JZOJ5459]【NOIP2017提高A组冲刺11.7】密室
  • 原文地址:https://www.cnblogs.com/lcfsih/p/14391400.html
Copyright © 2011-2022 走看看