POJ 3694 Network(双连通分量)

http://poj.org/problem?id=3694

题意 : N个点,M条边,构成一个连通图,将图中加入特定的一些边,每加一条边就输出加入这条边后图中剩的桥的个数。

思路 :双连通分量,用LCA

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;

const int maxn = 100005 ;
const int maxm = 555555 ;
const int INF = 1000000000 ;

struct Edge
{
    int v, next;
}map[maxm];

int low[maxn],dfn[maxn],index,vis[maxn] ;
int e,n,m,a,b,head[maxn] ;
int cnt,bridge[maxn],father[maxn] ;

void Init()
{
    e = 0 ; index = 0 ; cnt = 0 ;
    memset(vis,0,sizeof(vis)) ;
    memset(bridge,0,sizeof(bridge)) ;
    memset(dfn,0,sizeof(dfn)) ;
    memset(head,-1,sizeof(head)) ;
    for(int i = 1 ; i <= n ; i++)
    father[i] = i ;
}

void addedge(int v,int w)
{
    map[e].v = w ;
    map[e].next = head[v] ;
    head[v] = e++ ;
}

void tarjan(int u)
{
    vis[u] = 1 ;
    dfn[u] = low[u] = ++index ;
    for(int i = head[u] ; i+1 ; i = map[i].next)
    {
        int v = map[i].v ;
        if(!vis[v])
        {
            father[v] = u ;
            tarjan(v) ;
            low[u] = min(low[u],low[v]) ;
            if(low[v] > dfn[u])
            {
                cnt++ ;
                bridge[v] = 1 ;
            }
        }
        else if(vis[v] == 1 && v != father[u])
        low[u] = min(low[u],dfn[v]) ;
    }
    vis[u] = 2 ;
}

void lca(int u,int v)
{
    while(dfn[u] > dfn[v])
    {
        if(bridge[u]) cnt--,bridge[u] = 0 ;
        u = father[u] ;
    }
    while(dfn[v] > dfn[u])
    {
        if(bridge[v]) cnt--,bridge[v] = 0 ;
        v = father[v] ;
    }
    while(u != v)
    {
        if(bridge[u]) cnt--,bridge[u] = 0 ;
        if(bridge[v]) cnt--,bridge[v] = 0 ;
        u = father[u] ;
        v = father[v] ;
    }
}
int main()
{

    int kase = 0 ;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n == 0 && m == 0) break ;

        Init() ;
        while(m--)
        {
            scanf("%d %d",&a,&b) ;
            addedge(a,b) ;
            addedge(b,a) ;
        }
        tarjan(1) ;
        int k ;
        scanf("%d",&k) ;
        printf("Case %d:
",++kase) ;
        while(k--)
        {
            scanf("%d %d",&a,&b) ;
            lca(a,b) ;
            printf("%d
",cnt) ;
        }
        printf("
") ;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/luyingfeng/p/3543496.html