POJ3352
题解:
- 至少加几条边,才能使任意两点之间至少有两条不同的路可以走,也就是边-双连通。题目中没有重边。
- Tarjan缩点,再求出入度为1的点的个数s。要加的边为(s + 1)/ 2。【网上找的公式,找不到证明】
代码:
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
using namespace std;
int const N = 1000 + 10;
vector<int>G[N];
int n,m,cnt,scc,pre[N],lowlink[N],sccno[N];
int in[N];
stack<int>st;
void Init(){
for(int i=1;i<=n;i++)G[i].clear();
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
}
void dfs(int u,int fa){
pre[u] = lowlink[u] = ++cnt;
st.push(u);
int num = 0;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v == fa) continue; //没有重边
if(!pre[v]){
dfs(v,u);
lowlink[u] = min(lowlink[v],lowlink[u]);
}else if(!sccno[v]){
lowlink[u] = min(lowlink[u],pre[v]);
}
}
if(pre[u] == lowlink[u]){
scc++;
while(1){
int x = st.top(); st.pop();
sccno[x]= scc;
if(x == u) break;
}
}
}
void Tarjain(){
cnt = scc = 0;
while(!st.empty()) st.pop();
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
dfs(1,0);
memset(in,0,sizeof(in));
for(int i=1;i<=n;i++){
for(int j=0;j<G[i].size();j++){
int v = G[i][j];
if(sccno[i] != sccno[v]) in[sccno[v]]++;
}
}
int s = 0;
for(int i=1;i<=scc;i++){
if(in[i] == 1) s++;
}
printf("%d\n",(s+1)/2);
}
int main(){
while(cin>>n>>m){
Init();
Tarjain();
}
}