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;
    }
  • 相关阅读:
    eclipse中如何复制用点分隔的全类名
    win7 64下暗黑世界V1.1 服务器端及客户端的安装及运行 成功
    Firefly Http通信简单介绍
    win7 不能启动 memcached 总是反回failde to start service
    win7 安装 memcached
    memcached完全剖析–1. memcached的基础
    【Firefly API 新版文档】Package dbentrust
    《暗黑世界GM管理后台系统》部署+功能说明
    [官方教程] 暗黑世界 客户端 配置文档
    MAC下《暗黑世界》客户端版本编译说明!!
  • 原文地址:https://www.cnblogs.com/captain1/p/9758119.html
Copyright © 2011-2022 走看看