zoukankan      html  css  js  c++  java
  • poj3352

    题意:本题要求的就是添加多少条边可变无桥的连通图。分析:双连通分支双连通分支分就是一个极大化(一个点只要加进来之后该分支仍然是双连通分支就加进来)的分支,去掉任意一条边这个分支内部仍然连通。

    也可以理解为去掉桥之后,每个连通分支就是原图的双连通分支。

    注意:北大培训中说有两种双连通(边的和点的),其实只有边的双连通才是双连通的正规定义。所以我们不对点的双连通进行讨论。

    求割点和桥可以用tarjan算法,对图进行dfs,记录每个点的第一次到达时间dfn[i]。并记录一个low[i]表示该点及其子孙结点所能到达的dfn最小的点。这个到达并不是普通意义的到达,而是在遍历过程中,通过非树枝边(一定是返祖边,因为是无向图,没有横叉边)能够直接到达的点(而不是连续使用返祖边能到达的)。这样就可以把low总结为low[u] = min(low[v](v为u的儿子结点),dfn[v](v是u通过返祖边能到达的点),dfn(u));然后我们可以粗略地认为返祖边可以连同树枝边共同构成一个环。环一定是双连通的(一定不是桥),不在环内的边一定是桥。 这样我们就可以总结为:若边(u,v),dfn[u]<low[v](即不在环内),则为桥。

    另外有定理,当把边的双连通分支缩点后形成了一个有向无环图,叶子(度为1的点)的个数为n,则需要在原图中添加(n + 1)/2条边,可以使原图变为没有桥的双连通图。

     

    View Code
    #include <iostream>
    #include
    <cstdio>
    #include
    <cstdlib>
    #include
    <cstring>
    usingnamespace std;

    #define maxn 5005
    #define maxm 10005

    struct Edge
    {
    int v, next;
    } edge[maxm];

    int n, m;
    int head[maxn];
    bool hash[maxn][maxn];
    int ecount, tcount;
    int dfn[maxn], vis[maxn], low[maxn], degree[maxn];

    void addedge(int a, int b)
    {
    edge[ecount].v
    = b;
    edge[ecount].next
    = head[a];
    head[a]
    = ecount;
    hash[a][b]
    = hash[b][a] =true;
    ecount
    ++;
    }

    void input()
    {
    memset(head,
    -1, sizeof(head));
    ecount
    =0;
    scanf(
    "%d%d", &n, &m);
    for (int i =0; i < m; i++)
    {
    int a, b;
    scanf(
    "%d%d", &a, &b);
    a
    --;
    b
    --;
    if (hash[a][b])
    continue;
    addedge(a, b);
    addedge(b, a);
    }
    }

    void dfs(int fa, int u)
    {
    vis[u]
    =true;
    low[u]
    = dfn[u] = tcount++;
    for (int i = head[u]; i !=-1; i = edge[i].next)
    {
    int v = edge[i].v;
    if (v == fa)
    continue;
    if (!vis[v])
    dfs(u, v);
    low[u]
    = min(low[u], low[v]);
    }
    }

    int tarjan()
    {
    memset(dfn,
    0, sizeof(dfn));
    memset(vis,
    0, sizeof(vis));
    memset(degree,
    0, sizeof(degree));
    tcount
    =0;
    dfs(
    0, 0);
    int ret =0;
    for (int i =0; i < n; i++)
    for (int j = head[i]; j !=-1; j = edge[j].next)
    {
    int v = edge[j].v;
    if (low[i] != low[v])
    degree[low[i]]
    ++;
    }
    for (int i =0; i < n; i++)
    if (degree[i] ==1)
    ret
    ++;
    return (ret +1) /2;
    }

    int main()
    {
    //freopen("t.txt", "r", stdin);
    input();
    int ans = tarjan();
    printf(
    "%d\n", ans);
    return0;
    }
  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/rainydays/p/2099516.html
Copyright © 2011-2022 走看看