zoukankan      html  css  js  c++  java
  • Tarjan求桥

    传送门(poj3177)

    这道题是Tarjan求桥的模板题。大意是要求在原图上加上数量最少的边,使得整张图成为一个边双联通分量。

    具体的做法是,先在图中求出所有的桥,之后把边双联通分量缩成点,这样的话原图就变成了一棵树。之后,我们就在叶子之间加边即可。如何加最少的边呢?好像第一眼看上去,随便在两个叶子中间加一条边就能减少两个叶子,但事实上不是这样的,如果这两个叶子中间的路径数小于等于1条的话,将新形成的边双联通分量缩点之后有可能出现新的叶子。就像这张图一样,如果连接红色的边,那么新的图会多出一个叶子。

    这个是因为路径上的边数只有一条,如果我们选择两点路径上边数大于1的两个叶子合并,那么一定会形成一个新的边双联通分量,而且不会有新的叶子。

    因为这样的话那个新的边双肯定是至少有两个度的,那他就不会成为叶子,而如果只有一条的话,它的度就是1,那么就形成新的叶子了。

    我们要这样去合并:

    这样就可以啦!所以我们最后能得出的结论就是,需要加的边数=(叶子个数+1) >> 1.

    那我们直接求桥,之后缩点,求出每个点最后的度然后计算一下就行。

    然后这题因为有重边就很难受……一开始我是直接判断如果是父亲就不管,但是这样不行……因为有重边的就不是桥了,他是需要父亲去更新的,所以后来判断一下,只有树边的那条反向边我们给他特判掉,其他的都能正常更新。

    看一下代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 10000005;
     
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,to,from;
    }e[M];
    
    int f,r,x,y,ecnt = -1,head[M],dfn[M],low[M],scc[M],stack[M],top,cnt,rdeg[M],ans,idx;
    bool vis[M],pd[M];
    
    void add(int x,int y)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    }
    
    void tarjan(int x,int g)
    {
        bool flag = 0;
        vis[x] = 1,stack[++top] = x;
        dfn[x] = low[x] = ++idx;
        for(int i = head[x];~i;i = e[i].next)
        {
        //if(pd[i]) continue;
        //pd[i] = pd[i^1] = 1;
        if(e[i].to == g && !flag)
        {
            flag = 1;
            continue;
        }
        if(!dfn[e[i].to]) tarjan(e[i].to,x),low[x] = min(low[x],low[e[i].to]);
        else if(vis[e[i].to])low[x] = min(low[x],dfn[e[i].to]);
        }
        if(low[x] == dfn[x])
        {
        int p;
        cnt++;
        while((p = stack[top--]))
        {
            scc[p] = cnt,vis[p] = 0;
            if(p == x) break;
        }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        f = read(),r = read();
        rep(i,1,r) x = read(),y = read(),add(x,y),add(y,x);
        rep(i,1,f) if(!dfn[i]) tarjan(i,i);
        rep(i,1,f)
        {
        for(int j = head[i];~j;j = e[j].next)
        {
            int r1 = scc[e[j].to],r2 = scc[i];
            if(r1 != r2) rdeg[r1]++,rdeg[r2]++;
        }
        }
        rep(i,1,cnt) if(rdeg[i] == 2) ans++;
        printf("%d
    ",(ans+1) >> 1);
        return 0;
    }
  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/captain1/p/9758119.html
Copyright © 2011-2022 走看看