poj 3177 Redundant Paths (边双联通分量+缩点)

题意:

大意说要在现有的图中加几条边使得整个图都是双联通分量。

题解:

跑一边Tarjan同时缩点,根据缩点完后的图,找出度为1的点的个数cnt,这个点肯定是桥的缩点,那么要满足题意,要添加的边数为:(cnt+1)/2;

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
const int oo=0x3f3f3f3f;
const int MOD=1000000007;
const int maxn=5100;
const int maxm=21000;
struct EDGE{
    int v,next,c,f;
}E[maxm];
int head[maxn],tol;
int low[maxn],dfn[maxn];
int fa[maxn],bridge[maxm];
int id[maxn],d[maxn];
int g_cnt,bcnt,ID;

void Init(){
    memset(head,-1,sizeof head);
    tol=0;
    memset(low,0,sizeof low);
    memset(dfn,0,sizeof dfn);
    memset(d,0,sizeof d);
    g_cnt=bcnt=ID=0;
    for(int i=0;i<maxn;i++)fa[i]=i;
}

void add_edge(int u,int v){
    E[tol].v=v;
    E[tol].next=head[u];
    head[u]=tol++;
}

int Find(int x){
    if(fa[x]==x)return x;
    return fa[x]=Find(fa[x]);
}

void Merge(int x,int y){
    int fx=Find(x);
    int fy=Find(y);
    fa[fx]=fy;
}

void Tarjan(int u,int pre){
    dfn[u]=low[u]=++g_cnt;
    for(int i=head[u];i!=-1;i=E[i].next){
        int v=E[i].v;
        if(v==pre)continue;
        if(!dfn[v]){
            Tarjan(v,u);
            if(low[v]<low[u])
                low[u]=low[v];
            if(low[v]>dfn[u])
                bridge[bcnt++]=i;
            else
                Merge(u,v);
        }else if(dfn[v]<low[u])
            low[u]=dfn[v];
    }
}

void gao(int n){
    memset(id,-1,sizeof id);
    for(int i=1;i<=n;i++){
        int u=Find(i);
        if(id[u]==-1)
            id[u]=++ID;
        id[i]=id[u];
    }
    for(int i=0;i<bcnt;i++){
        int j=bridge[i];
        int u=E[j^1].v;
        int v=E[j].v;
        u=id[u];
        v=id[v];
        d[u]++;
        d[v]++;
    }
    int cnt=0;
    for(int i=1;i<=ID;i++){
        if(d[i]==1)cnt++;
    }
    printf("%d\n",(cnt+1)/2);
}

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int n,m,u,v;
    while(scanf("%d %d",&n,&m)!=EOF){
        Init();
        for(int i=1;i<=m;i++){
            scanf("%d %d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        Tarjan(1,-1);
        gao(n);
    }
    return 0;
}



你可能感兴趣的:(算法,网络,poj)