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

    /*
    *State: ZOJ2588 530 MS    12788 KB    GNU C++
    *题目大意:
    *        给出一个无向图,输入n(表示n个定点,1~n), m(m条边,有重边),
    *        (2 <= N <= 10 000, 1 <= M <= 100 000),求这个无向图中的桥,
    *        并输出桥属于输入中边的id.
    *解题思路:
    *        知道求割点与求割边是很相似的,自己用笔模拟一下就知道,如果
    *        存在low[v] > dfn[u].那么uv就是割边。看似与割点异常类似,但是
    *        用了原始的求割点的tarjan敲了几遍后发现,不行。因为求割点的时
    *        候由于条件是low[v] >= dfn[u],所以它可能回溯回自己的父亲节点,
    *        然后就更新了自己的low[v].之后求割边的条件就实现不出来了。
    *
    *        发现了这个问题之后,就修改了tarjan算法,把参数由一个当前节点
    *        改为2个,一个父亲结点,一个它自己,然后搜。将一个节点的所有孩
    *        子节点都搜一遍,之后再判断,只要dfn[n] == low[n],就说明n跟它
    *        的父亲节点构成的边是割边。为什么?因为dfn[n] == low[n],就说明
    *        当前节点n的所有孩子节点都最多只能到达当前节点n的孩子节点。也就
    *        是说n跟它的father是关节边。
    *
    *        ps:为什么求割点是把判断放在循环内,求割边要放在循环外(其实放
    *        循环外面也可以,但是要注意回溯判断的不同,要修改根节点的情况)。
    *        用笔模拟下即可。该题有重边,我先把它当无重边算,之后在判断割边
    *        的时候判断下是否为重边即可。
    */
    View Code
    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <algorithm>
    #include <utility>
    #include <cstring>
    using namespace std;
    
    typedef struct _node
    {
        int v, id, num;
        _node():num(0) {};
    }N;
    
    const int MAX = 10005;
    vector<N> vec[MAX];
    int dfn[MAX], low[MAX], step, id;
    int ans[MAX * 10], cnt;
    
    void addEdge(int u, int v)
    {
        bool flag = false;
        for(unsigned i = 0; i < vec[u].size(); i++)
        {
            if(vec[u][i].v == v)
            {
                flag = true;
                vec[u][i].num++;
                for(unsigned j = 0; j < vec[v].size(); j++)
                {
                    if(vec[v][j].v == u)
                    {
                        vec[v][j].num++;
                        break;
                    }
                }
                id++;
                break;
            }
        }
        if(flag == false)
        {
            N tmp;
            tmp.v = v, tmp.id = id++;
            tmp.num = 1;
            vec[u].push_back(tmp);
            tmp.v = u;
            vec[v].push_back(tmp);
        }
    }
    
    void tarjan(int father, int n)
    {
        dfn[n] = low[n] = ++step;
        for(unsigned i = 0; i < vec[n].size(); i++)
        {
            int son = vec[n][i].v;
            if(dfn[son] == -1)
            {
                tarjan(n, son);
                low[n] = min(low[n], low[son]);
            }
            else if(son != father)
                low[n] = min(low[n], dfn[son]);
        }
    
        if(dfn[n] == low[n])
        {
            int son = n;
            n = father;
            for(unsigned k = 0; k < vec[n].size(); k++)
            {
                if(son == vec[n][k].v)
                {
                    if(vec[n][k].num == 1)
                    {
                        ans[cnt++] = vec[n][k].id;
                    }
                    break;
                }
            }
        }
    }
    
    void init()
    {
        id = 1;
        step = cnt = 0;
        for(int i = 0; i < MAX; i++)
        {
            vec[i].clear();
            dfn[i] = low[i] = -1;
        }
    }
    
    int main(void)
    {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
    #endif
    
        int cas;
        scanf("%d", &cas);
        while(cas--)
        {
            init();
            int n, m;
            scanf("%d %d", &n, &m);
            for(int i = 0; i < m; i++)
            {
                int u, v;
                scanf("%d %d", &u, &v);
                addEdge(u, v);
            }
            dfn[1] = low[1] = ++step;
            tarjan(1, 1);
    
            printf("%d\n", cnt);
            if(cnt)
            {
                sort(ans, ans + cnt);
                printf("%d", ans[0]);
                for(int i = 1; i < cnt; i++)
                {
                    printf(" %d", ans[i]);
                }
                printf("\n");
            }
            if(cas)
                printf("\n");
        }
        return 0;
    }
  • 相关阅读:
    SQL server 插入不同IP的数据库
    SQL Server中的循环例子(网摘)
    C#小型数据库只能查询
    vue.prototype和vue.use的区别和注意点
    Ajax+PHP简单入门教程
    smarty在windows下的安装
    docker安装mysql镜像和容器
    Linux导出未越狱Iphone10.3QQ聊天记录
    记一次Struts中文乱码
    Ubuntu设置服务开机启动
  • 原文地址:https://www.cnblogs.com/cchun/p/2645077.html
Copyright © 2011-2022 走看看