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