再来点boss
给定一个 n 个点 m 条边的无向图,保证图连通。找到两个点 s,t ,使得 s 到 t 必须经过的边最多(一条边无论走哪条路线这一条边都经过,这条边就是必须经过的边)。
首先我们要知道知道同一个边双连通分量中,任意两点之间存在至少两条无重边的简单路径。
我们可以发现同一个边双内的点之间没有必须经过的边。所以在这一道题目中,我们只需要把给我们的图给缩点缩成一棵树,然后跑两边 dfs 求树的直径即可,也就是 2 个板子套一下就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=1200100;
int n,m,idx=1,cnt,in1,in2,num,p,q;
int to[N],nxt[N],head[N],rhead[N];
int dfn[N],low[N],bridge[N],rid[N];
int dis[N];
void add(int h[],int u,int v)
{
idx++;
to[idx]=v;
nxt[idx]=h[u];
h[u]=idx;
}
void tarjan(int s,int last)//缩点板子,不必多说
{
dfn[s]=low[s]=++cnt;
for(int i=head[s];i;i=nxt[i])
{
int v=to[i];
if(i==(last^1))
continue;
if(!dfn[v])
{
tarjan(v,i);
low[s]=min(low[s],low[v]);
if(dfn[s]<=low[v])//直接就是一座桥
{
bridge[i]=bridge[i^1]=1;
}
}
else
low[s]=min(low[s],dfn[v]);
}
}
void dfs_0(int s)//跑2遍dfs,求树的直径
{
rid[s]=num;
for(int i=head[s];i;i=nxt[i])
{
int v=to[i];
if(bridge[i]||rid[v])
continue;
dfs_0(v);
}
}
void dfs_1(int s,int fa,int &u)
{
for(int i=rhead[s];i;i=nxt[i])
{
int v=to[i];
if(v==fa)
continue;
dis[v]=dis[s]+1;
if(dis[0]<dis[v])
{
dis[0]=dis[v];
u=v;
}
dfs_1(v,s,u);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&in1,&in2);
add(head,in1,in2);
add(head,in2,in1);
}
tarjan(1,-1);
for(int i=1;i<=n;i++)
{
if(!rid[i])
{
num++;
dfs_0(i);
}
}
for(int s=1;s<=n;s++)
{
for(int i=head[s];i;i=nxt[i])
{
if(rid[s]!=rid[to[i]])
{
add(rhead,rid[s],rid[to[i]]);
}
}
}
dis[1]=0;
dfs_1(1,0,p);
dis[0]=dis[p]=0;
dfs_1(p,0,q);
cout<<dis[0]<<endl;
return 0;
}