问 题 Ⅰ . 无 向 图 必 经 点 \color{Red}问题Ⅰ.无向图必经点 问题Ⅰ.无向图必经点

无向图给定 a , b a,b a,b,找出哪些点是 a , b a,b a,b路上的必经点.

算法Ⅰ.针对固定的u,v,找所有的必经点

​问题传送门​

首先必经点一定是割点,否则移除那个点,对图的连通性无影响

首先从点 a a a开始 t a r j a n tarjan tarjan,制造出一颗 d f s dfs dfs搜索树

若由于某个儿子 v v v判断了 u u u是割点,删去点 u u u后 v v v子树都会和 a a a丧失联系

这个非常重要,因为这就是判断割点的定义,不通过回边回到更浅节点

所以当我们去 t a r j a n tarjan tarjan那个 u u u的子树 v v v发现 u u u是割点

那么若 b b b也在 v v v的子树内说明 a , b a,b a,b丧失了联系

也就是去判断 d f n [ v ] < = d f n [ b ] dfn[v]<=dfn[b] dfn[v]<=dfn[b]且是割点

很简单,如果 b b b没有被 t a r j a n tarjan tarjan到, d f n [ b ] = 0 dfn[b]=0 dfn[b]=0,不可能满足

如果 b b b早就被 t a r j a n tarjan tarjan到了,那么 d f n [ b ] dfn[b] dfn[b]会比较小才对

否则,就是我们的判断条件了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5+10;
struct edge{ int to,nxt; }d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){ d[++cnt] = (edge){v,head[u]},head[u] = cnt; }
int dfn[maxn],low[maxn],cut[maxn],id,n,a,b;
void tarjan(int u,int fa)
{
dfn[u] = low[u] = ++id;
int flag = 0;
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]&&u!=a&&u!=b )//割点,不通过点u到更浅的节点
{
if( dfn[v]<=dfn[b] ) cut[u] = 1;
}
}
else
{
if( flag||v!=fa ) low[u] = min( low[u],dfn[v] );
else flag = 1;
}
}
}
int main()
{
cin >> n;
for(int i=1;;i++)
{
int l,r; cin >> l >> r;
if( l+r==0 ) break;
add(l,r); add(r,l);
}
cin >> a >> b;
tarjan(a,0);
int flag = 0;
for(int i=1;i<=n;i++)
if( cut[i] )
{
cout << i;
return 0;
}
cout << "No solution";
}

算法Ⅱ.在线判断必须边,必须点

​传送门​