码迷,mamicode.com
首页 > 编程语言 > 详细

图算法之(割边/桥)

时间:2017-09-26 13:09:10      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:开始   root   一个   暴力   遍历   nts   clu   算法   add   

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

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

所以当一个点(设为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;
}

 

图算法之(割边/桥)

标签:开始   root   一个   暴力   遍历   nts   clu   算法   add   

原文地址:http://www.cnblogs.com/star-eternal/p/7595894.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!