UVA - 796 Critical Links (tarjan,无向图桥)

女生的网名这么多〃 提交于 2019-11-26 07:40:32

题意:给出一个无向图,然后你要输升序输出该图中 所有的桥。

思路:使用tarjan对桥的求法性质:

当且仅当无向边(u,v)为树枝的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u-v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥。            

如果v能上翻到u那么u-v就是一个环,删除其中一条路径后,能然是连通的。所以最总就是使用low(v)>dfn(u)来判断是否为桥

完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;const int maxn = 1e3+10;
const int max_edge = 1e6+5;
struct Edge
{
    int to, next;
    bool cut;
}edge[max_edge];
int tot, head[maxn];
int id, dfn[maxn], low[maxn];
int num;
void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    edge[tot].cut = false;
    head[u] = tot++;
}
//tarjan的割边求法 
void tarjan(int u, int f)
{
    //时间戳更新 
    dfn[u] = low[u] = ++id;
    for(int i = head[u]; i!=-1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == f) continue;
        //深搜已经更新low值 
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            //tarjan算法割边确定的结论low[v]>dfn[u](桥>,割点>=) 
            if(low[v]>dfn[u])
            {         //由于无向图边是连着存的,所以就用 ^ 得到所用有向边代替的另一个边 (0^1=1, 1^1=0),网上看到大佬的写法         //当然我们也可以使用 奇数向下取偶,偶数向上取奇 
                edge[i].cut = edge[i^1].cut = true;
                num++;
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}
void init()
{
     id = num = tot = 0;
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
}
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        init();
        int u, m, v;
        for(int i = 1; i<=n; i++)
        {
            scanf("%d (%d)", &u, &m);
            for(int j = 1; j<=m; j++)
            {
                scanf("%d", &v);
                addedge(u, v);
                addedge(v, u);
            }
        }
        for(int i = 0; i<n; i++)
            if(!dfn[i])
                tarjan(i, i);

        vector<pair<int, int> >a;
        for(int u = 0; u<n; u++)
        for(int i = head[u]; i!=-1; i = edge[i].next)
        {
            //按升序排列
            if(edge[i].cut && u < edge[i].to)
                a.push_back(make_pair(u, edge[i].to));
        }
        sort(a.begin(), a.end());
        printf("%d critical links\n", num);
        for(int i = 0; i<a.size(); i++)
            printf("%d - %d\n", a[i].first, a[i].second);
        printf("\n");
    }
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!