传送门
非常裸的一题
就是边双连通缩点成一棵树,然后树上所有边都是桥
那么连接任意两点,树的路径上都不再是桥
所以就找树的直径即可
但是这里会出现重边,那么需要特殊的处理方式
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 2e6+10;
const int N = 2e5+10;
int n,m;
vector<int>vec[N];
struct edge{
int u,to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
d[++cnt].u=u,d[cnt].to=v,d[cnt].nxt = head[u],head[u] = cnt;
}
int id,dfn[N],low[N],bridge[maxn],bcc[N],bccn,qiao;
int vis[N],stac[N],top;
void tarjan(int u,int fa)
{
bool flag=0;
dfn[u]=low[u]=++id; stac[++top]=u, vis[u] = 1;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( !dfn[v] )
{
tarjan(v,u);
low[u]=min( low[u],low[v] );
if( low[v]>dfn[u] )
qiao++,bridge[i]=bridge[i^1] = 1;
}
else if( vis[v] )//不通过父子回边,或者这条边有重边
{
if( v!=fa||flag )
low[u]=min( low[u],dfn[v] );
else flag=1;
}
}
if( low[u]==dfn[u] )
{
int temp; bccn++;
while( temp=stac[top--] )
{
vis[temp] = 0;
bcc[temp]=bccn;//属于哪个双连通
if( temp==u ) break;
}
}
}
int f[N],g[N],ans;
void dfs(int u,int fa)
{
vis[u] = 1;
for(int i=0;i<vec[u].size();i++)
{
int v = vec[u][i];
if( vis[v] ) continue;
dfs( v,u );
if( f[v]+1>=f[u] )
g[u] = f[u], f[u] = f[v]+1;
else if( f[v]+1>g[u] ) g[u] = f[v]+1;
}
ans = max( ans,f[u]+g[u] );
}
int main()
{
while( cin >> n >> m && (n+m) )
{
for(int i=1;i<=m;i++)
{
int l,r; scanf("%d%d",&l,&r);
add(l,r); add(r,l);
}
tarjan(1,1);
for(int i=2;i<=cnt;i++)
{
int u = d[i].u, v = d[i].to;
if( bcc[u]!=bcc[v] )
vec[bcc[u]].push_back(bcc[v]);
}
dfs(1,0);
cout << qiao-ans << endl;
for(int i=1;i<=n;i++)
vec[i].clear(), f[i] = g[i] = vis[i] = head[i] = dfn[i] = low[i] = 0;
for(int i=1;i<=cnt;i++) bridge[i] = 0;
cnt = 1; ans = bccn = id = qiao = top = 0;
}
}