图算法之(割边/桥)

Posted star_eternal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图算法之(割边/桥)相关的知识,希望对你有一定的参考价值。

栈里面的点,它在整个过程中始终是从根到当前点的一条链

在所有访问过的点(红点和绿点)中,只有它们是可能扩展出未被访问的点的。

所以当一个点(设为u退栈的时候,考虑假设以这个点为根,能遍历到的点组成的集合,只会有两种情况:
1. 这个点已经被访问过了(变成红色或者绿色)
2. 这个点(设为v)还是黑色的,但是一定存在另一个红点(设为x),能够在不走红边的情况下访问到它,即
一定存在一条路径 u=>x=>v;

给定无向图的点(N)和边(M),输出图中所有的桥(按小编号排序)。

N<=2000
注意:重边算一条
输入:
10 17
2 1
2 6
2 8
3 2
3 5
4 2
4 7
5 3
5 4
6 3
7 1
7 2
7 3
7 5
8 2
9 6
10 8
输出:
3
2 8
6 9
8 10
样例第一行两个数分别表示点数和边数,接下来M行表示M条边。输出第一行为桥的个数,接下来每行两个数表示桥。

这道题,暴力不说了,直接说正规算法

定理:一个边是割边当且仅当他是树边并且他的开始节点的时间戳小于其后继节点的子树的所能找到的最早的节点。

自己证明。(*^▽^*)=>(#`O′)=>(╯‵□′)╯︵┻━┻

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000+10
using namespace std;
int head[N],num;
struct edge{
    int next,to;
};
struct data{
    int x,y;
};
data ss[2*N*(N-1)];
edge e[2*N*(N-1)];
void add(int from,int to)
{
    e[++num].next=head[from];
    e[num].to=to;
    head[from]=num;
}
int flag[N],dfn[N],low[N];
int bu[N],bv[N];
int tim=0,tot;
int cnt=0;
int cmp(const data & a,const data & b)
{
    if(a.x<b.x)return 1;
    if(a.x>b.x)return 0;
    if(a.y<b.y)return 1;
    return 0;
}
void tarjan_CE(int u,int fa)
{
    //vis[u]=1;
    tim++;
    low[u]=dfn[u]=tim;
//    int son=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        //if(v==fa)continue;
        if(!dfn[v])
        {
//            son++;
            tarjan_CE(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
            {
                ss[++cnt].x=u,ss[cnt].y=v;
            }    //flag[u]=1;
//            if(u==root&&son>=2)
//            {
//                ss[++cnt].x=u,ss[cnt].y=v;    
//            }
        }
        else if(v!=fa)
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    return;
}
int main()
{
//    freopen("sss.in","r",stdin);
//    freopen("sss.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
//        if(!book[x][y]and!book[y][x])
//        {
            add(x,y);
            add(y,x);
//            book[x][y]=book[y][x]=1;
//        }        
    }
    cnt=0;
    tarjan_CE(1,1);
    sort(ss+1,ss+cnt+1,cmp);
//    for(int i=1;i<=n;i++)
//    {
//        if(flag[i]==1)cnt++;
//        //printf("%d ",i);
//    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
    {
        //if(!book[ss[i].x][ss[i].y]&&!book[ss[i].y][ss[i].x])
            printf("%d %d\n",ss[i].x,ss[i].y);
        //book[ss[i].x][ss[i].y]=    book[ss[i].y][ss[i].x]=1;
    }
//    fclose(stdout);
    return 0;
}

 

以上是关于图算法之(割边/桥)的主要内容,如果未能解决你的问题,请参考以下文章

[啊哈算法]关键道路(图的割边)

UVA 796 Critical Links —— (求割边(桥))

[POJ3177]Redundant Paths(双连通图,割边,桥,重边)

割边 + 缩点(得到边连通分量) + 朴素LCA

tarjan求割边割点

HDU4738 Caocao's Bridges强连通