luooj P1226 修橋

題目鏈接
分析
雙聯通割邊,依舊縮點,好像並沒有用到橋的數量,不過作爲一道模版題還是打了。詳細見我註釋的代碼

#include<bits/stdc++.h>
#define N 5005
#define M 20005
using namespace std;
int tot,head[N],Next[M],vet[M];
void add(int x,int y){
    tot++;
    vet[tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}//邊表連邊
stack <int> s;
int m,n,ans,bcc,bcc_cnt,bccno[N],in[N];
int dfs_clock,low[N],dfn[N];
void Tarjan(int u,int fa){
    int cnt=0;s.push(u);
    dfn[u]=low[u]=++dfs_clock;
    for(int i=head[u];i;i=Next[i]){
        int v=vet[i];
        if(v==fa && ++cnt==1)continue;//此處用於判斷連邊是否有回邊,就是說在連邊時本來就有一條回邊,但是題目可能還有別的回邊。 
        if(!dfn[v]){
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) bcc++;//畫圖找規律,就發現這就是橋的數量
        }else
            if(dfn[v]<dfn[u])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        bcc_cnt++;
        for(;;){
            int v=s.top();s.pop();
            bccno[v]=bcc_cnt;
            if(u==v)break;
        }
    }//另外和強聯通分量的模版基本一樣
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])Tarjan(i,-1);
    for(int u=1;u<=n;u++)
        for(int i=head[u];i;i=Next[i]){
            int v=vet[i];
            if(bccno[u]!=bccno[v])
            in[bccno[v]]++;
        }//記錄縮點後的入度
    for(int i=1;i<=bcc_cnt;i++)
        if(in[i]==1)ans++;
    printf("%d",(ans+1)/2);//根節點數+1/2是連邊數。
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章