POJ 3177 Tarjan e-DCC

题意

传送门 POJ 1377 Redundant Paths

题解

向图中添加数量最少的边,使整个图构成边双连通分量。

T a r j a n Tarjan Tarjan 算法求解割边, e − D C C e-DCC eDCC 缩点,构成一棵树。对路径的端点连边,显然比对路径中的点连边,影响的点更多,使答案更优。考虑度为 1 1 1 的点,任一对这样的点 x , y x,y x,y 连边,都将使路径 ( x , l c a ( x , y ) , ( l c a ( x , y ) , y ) (x,lca(x,y),(lca(x,y),y) (x,lca(x,y),(lca(x,y),y) 中的点满足至少在一个环上。设新图中度为 1 1 1 的点数为 c n t cnt cnt,则答案为 ⌈ c n t / 2 ⌉ \lceil cnt/2\rceil cnt/2

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 5005, maxm = 10005 * 2;
int N, M, num, dcc, bg[maxm], dfn[maxn], low[maxn], deg[maxn], dc[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];

inline void add(int x, int y) {
    
     to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }

void tarjan(int x, int in)
{
    
    
    dfn[x] = low[x] = ++num;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dfn[y])
        {
    
    
            tarjan(y, i);
            low[x] = min(low[x], low[y]);
            if (low[y] > dfn[x])
                bg[i] = bg[i ^ 1] = 1;
        }
        else if (i != (in ^ 1))
            low[x] = min(low[x], dfn[y]);
    }
}

void dfs(int x, int c)
{
    
    
    dc[x] = c;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dc[y] && !bg[i])
            dfs(y, c);
    }
}

int main()
{
    
    
    scanf("%d%d", &N, &M);
    tot = 1;
    for (int i = 1, x, y; i <= M; ++i)
        scanf("%d%d", &x, &y), add(x, y), add(y, x);
    for (int i = 1; i <= N; ++i)
        if (!dfn[i])
            tarjan(i, 0);
    for (int i = 1; i <= N; ++i)
        if (!dc[i])
            ++dcc, dfs(i, dcc);
    for (int i = 2; i <= tot; i += 2)
    {
    
    
        int x = dc[to[i]], y = dc[to[i ^ 1]];
        if (x != y)
            ++deg[x], ++deg[y];
    }
    int res = 0;
    for (int i = 1; i <= N; ++i)
        res += deg[i] == 1;
    printf("%d\n", (res + 1) >> 1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114868461