• poj 3177 Redundant Paths


    双连通分量

    题意:给一个无向图,问要添加多少条边形成边双连通分量。注意图一开始是连通的,所以只要从一个点开始dfs一次就行了,另外这图有重边,(1,2)(2,1)这样,则1,2就形成了一个边双连通分量。

    之前写的求边双连通分量的代码不能处理重边,但是要修改过来其实挺简单的。重边无非是遇到一个问题,从u走到v,按一般的做法,是不能从v回到u的,即不能马上就回到它父亲节点去(其实指的是不能重复走这条边,这条边虽然是无向边但是只能走一次),但是有了重边后,是可以马上回到它父亲处的,只不过走的是另一条边。所以我们可以标记哪些边用过了,每条边只能用一次,用过一次后不能再用。而且别忘了,建图的时候,无向边是分成两条有向边来保存的,所以当一条有向边被使用后,它对应的另一条反边也不能使用了,要一同标记(这样才起到了每条无向边只能走一次的效果),标记的方法很常用,e[k].used = e[k^1].used = 1;  神奇的位运算

    然后这个方格其实是个更好的方法,另外这样的代码,是能够同时处理有重边和无重边的情况的,所以就这样运行一下tarjan就能出结果

    #include <iostream>
    #include <vector>
    #include <utility>
    #include <stack>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 5010
    #define M 10010
    
    int n,tot;
    int head[N],dfn[N],low[N],belong[N],ins[N],de[N],dcnt,bcnt;
    typedef pair<int,int>pii;
    struct edge
    {
        int u,v,used,next;
    }e[2*M];
    vector<pii>bridge;
    stack<int>sta;
    
    void add(int u , int v , int k)
    {
        e[k].u = u; e[k].v = v; e[k].used = 0;
        e[k].next = head[u]; head[u] = k++;
        u = u^v; v = u^v; u = u^v;
        e[k].u = u; e[k].v = v; e[k].used = 0;
        e[k].next = head[u]; head[u] = k++;
    }
    
    void dfs(int u ,int fa)
    {
        dfn[u] = low[u] = ++dcnt;
        sta.push(u); ins[u] = 1;
        for(int k=head[u]; k!=-1; k=e[k].next)
            if(!e[k].used)
            {
                e[k].used = e[k^1].used = 1;
                int v = e[k].v;
                if(!dfn[v]) //树边
                {
                    dfs(v , u);
                    low[u] = min(low[u] , low[v]);
                    if(low[v] > dfn[u]) //
                    {
                        bridge.push_back(make_pair(u,v));
                        ++bcnt;
                        while(true)
                        {
                            int x = sta.top();
                            sta.pop(); ins[x] = false;
                            belong[x] = bcnt;
                            if(x == v) break;
                        }
                    }
                }
                else if(ins[v]) //后向边
                    low[u] = min(low[u] , dfn[v]);
            }
    }
    
    void solve()
    {
        bridge.clear();
        while(!sta.empty()) sta.pop();
        memset(ins,0,sizeof(ins));
        memset(dfn,0,sizeof(dfn));
        memset(de,0,sizeof(de));
        dcnt = bcnt = 0;
        dfs(1,-1);
        ++bcnt;
        while(!sta.empty())
        {
            int x = sta.top();
            sta.pop(); ins[x] = 0;
            belong[x] = bcnt;
        }
    
    //    for(int i=1; i<=n; i++)
    //        cout << i << "[" << low[i] << "]" << endl;
    
        for(int i=0; i<bridge.size(); i++)
        {
            int u = bridge[i].first;
            int v = bridge[i].second;
            de[belong[u]]++;
            de[belong[v]]++;
        }
        int leaf = 0;
        for(int i=1; i<=bcnt; i++)
            if(de[i] == 1)
                leaf++;
        cout << (leaf+1)/2 << endl;
    }
    
    int main()
    {
        while(cin >> n >> tot)
        {
            tot *= 2;
            memset(head,-1,sizeof(head));
            for(int i=0; i<tot; i+=2)
            {
                int u,v;
                cin >> u >> v;
                add(u,v,i);
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    偏函数 匿名函数 高阶函数 map filter reduce
    函数
    Python的字符串格式化
    集合
    列表 元组 字典
    字符串
    数字
    Python基础-杂项
    Java 和C/C++的“语法”上的差异!
    MySQL基础原创笔记(一)
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3087008.html
Copyright © 2020-2023  润新知