poj3177 Redundant Paths

題目大意:給一個連通圖,求最少加多少邊使它變成一個點聯通份量。ios

先找割邊,而後把沒有橋的點雙連通份量縮成一個連通份量。
git

這些連通份量按原來的關係連在一塊兒就是一顆樹。spa

把樹變成一個點雙聯圖圖須要加(葉節點數+1)/2個邊。code

問題是怎麼求點雙連通份量。blog

若是一個點的dfn=low,說明目前棧中的元素都須要彈出,成爲一個點雙連通份量。get

把他們記錄到結構體裏面就行了string

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <stack>
#define in(a) a=read()
#define MAXN 10010
#define REP(i,k,n)  for(int i=k;i<=n;i++)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m,ans;
int total=0,head[MAXN],nxt[MAXN<<1],to[MAXN<<1];//ÁÚ½Ó±í 
int ind,dfn[MAXN],low[MAXN],vis[MAXN<<1];//¸î±ß 
int num,bel[MAXN];//Ëõµã 
int du[MAXN];
stack <int> S;
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void tarjan(int u){
    S.push(u);
    dfn[u]=low[u]=++ind;
    for(int e=head[u];e;e=nxt[e]){
        if(e%2 && vis[e+1])  continue;
        if(!(e%2) && vis[e-1])  continue; 
        if(vis[e])  continue;
        vis[e]=1;
        if(!dfn[to[e]]){
            tarjan(to[e]);
            low[u]=min(low[u],low[to[e]]);
        }
        else  low[u]=min(low[u],dfn[to[e]]);
    }
    if(low[u]==dfn[u]){
        num++;
        int v;
        do{
            v=S.top();
            bel[v]=num;
            S.pop();
        }while(u!=v);
    }
    return ;
}
int main(){
    in(n),in(m);
    int a,b;
    REP(i,1,m)  in(a),in(b),adl(a,b),adl(b,a);
    tarjan(1);
    REP(u,1,n)
        for(int e=head[u];e;e=nxt[e])
            if(bel[u]!=bel[to[e]])
                du[bel[u]]++,du[bel[to[e]]]++;
    REP(i,1,num)  if((du[i]/2)==1)  ans++;
    cout<<(ans+1)/2;
    return 0;
}
相關文章
相關標籤/搜索