Road Construction POJ - 3352(边双连通图)

传送门

题意:给你n个点,r条无向边,问最少需要添加几条边使即使删除一条边,依旧能够从一点到达任意点

题解:无向图强连通建边,只要将整个图建成一个边双连通图,那么删除任意一条边依旧还是能够从一点到达任意点

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const double Pi=3.14159265;
const double e=2.71828182;
const int N=3e3+5;
const ull base=163;
const ll INF=0x3f3f3f3f;
using namespace std;
int head[N],nx[N],to[N];
int low[N],dfn[N];
int tot=1;
int vis[N];
int sta[N],size=0,num=0;
int com[N];
void add(int u,int v){
    to[tot]=v;
    nx[tot]=head[u];
    head[u]=tot++;
}
void dfs(int x,int step,int pre){
    vis[x]=1;
    dfn[x]=low[x]=step;
    sta[size++]=x;
    int flag=0;
    for(int i=head[x];i;i=nx[i]){
        int v=to[i];
        if(v==pre&&!flag){
            flag=1;
            continue;
        }
        if(!vis[v])dfs(v,step+1,x);
        if(vis[v]==1)low[x]=min(low[x],low[v]);
    }
    if(dfn[x]==low[x]){
        int k;
        num++;
        do{
            k=sta[--size];
            com[k]=num;
        }while(k!=x);
    }
}
void tarjan(int n){
    for(int i=1;i<=n;i++)
        if(!vis[i])dfs(i,0,-1);
}
int in[N],out[N];
void init(int n){
    tot=1;
    size=num=0;
    memset(head,0,sizeof(head));
    for(int i=1;i<=n;i++)vis[i]=in[i]=out[i]=0;
}
int main(){
    fio;
    //int oo=0;
    int n,r;
    while(cin>>n>>r){
        init(n);
        while(r--){
            int u,v;
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        tarjan(n);
       // cout<<"Output for Sample Input "<<++oo<<endl;
        for(int u=1;u<=n;u++){
            for(int i=head[u];i;i=nx[i]){
                int v=to[i];
                if(com[v]==com[u])continue;
                else{
                    in[com[v]]++;
                    out[com[u]]++;
                }
            }
        }
        int ans=0;
        for(int i=1;i<num;i++){
            //cout<<in[i]<<"  "<<out[i]<<endl;
            if(in[i]==1&&out[i]==1)ans++;
        }
        cout<<(ans+1)/2<<endl;
    }
    return 0;
}

 

posted @ 2018-04-03 22:35  采蘑菇的小西佬  阅读(110)  评论(0编辑  收藏  举报