有一個無向圖,問加一條邊以後最少還有多少個橋。
就是求多少可以消除多少個橋,可知答案就是縮點以後樹的直徑。
求樹的直徑用dfs TLE, bfs就AC了,學到了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int N = 200000 + 10;
const int M = 1000000 + 10;
int cnt[2],to[M*2][2],nt[M*2][2],h[N][2];
int n,m,a,b,top,stk[N],dfn[N],low[N],dfs_clock;
int bc,bcc[N],d[N],vis[N],s,mam;
void add(int u,int v,int idx){
to[++cnt[idx]][idx] = v;
nt[cnt[idx]][idx] = h[u][idx];
h[u][idx] = cnt[idx];
}
void bfs(int root){
memset(vis,0,sizeof(vis));
queue<int> Q;
vis[root] = 1;
d[root] = 1;
Q.push(root);
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i = h[u][1] ; i ; i = nt[i][1]){
int v = to[i][1];
if(!vis[v]){
d[v] = d[u] + 1;
if(d[v] > mam) mam = d[v] , s = v;
vis[v] = 1;
Q.push(v);
}
}
}
}
void tarjan(int u,int fa){
low[u] = dfn[u] = ++ dfs_clock;
stk[++top] = u;
int mul = 0 ;
for(int i = h[u][0] ; i ; i = nt[i][0]){
int v = to[i][0];
if(v == fa && !mul){
mul ++ ; continue;
}
if(!dfn[v]){
tarjan(v, u);
low[u] = min(low[u] , low[v]);
}
else if(!bcc[v]) low[u] = min(low[u] , dfn[v]);
}
if(low[u] == dfn[u]) {
bc++;
while(1){
int t = stk[top--];
bcc[t] = bc;
if(u == t) break;
}
}
}
int main(){
freopen("data.in","r",stdin);
while(scanf("%d%d",&n,&m) && (m + n)){
memset(h,0,sizeof(h));
memset(cnt,0,sizeof(cnt));
memset(dfn,0,sizeof(dfn));
memset(bcc,0,sizeof(bcc));
top = dfs_clock = bc = 0;mam = -1;
for(int i = 0 ; i < m ;i ++) {
scanf("%d%d",&a,&b);
add(a,b,0);
add(b,a,0);
}
for(int i = 1; i <= n ;i ++)
if(!dfn[i]) tarjan(i,-1);
//for(int i = 1; i <= n ;i++) cout<<dfn[i]<<' ';cout<<endl;
//for(int i = 1; i <= n; i++) cout<<low[i]<<' ';cout<<endl;
//for(int i = 1; i <= n; i++) cout<<bcc[i]<<' ';cout<<endl;
for(int i = 1; i <= n ;i ++){
for(int j = h[i][0] ; j ;j = nt[j][0]){
int v = to[j][0];
if(bcc[i] == bcc[v]) continue;
add(bcc[i],bcc[v],1);
add(bcc[v],bcc[i],1);
}
}
if(bc == 1) {
printf("0\n");
continue;
}
bfs(1);
mam = -1;
bfs(s);
printf("%d\n",bc-mam);
}
return 0;
}