在许多题目中,常常都需要一下操作:给出S、T,找一个桥边(或必经点)
Solution1
先从S走到T,记录下路径(包括点和边),并且标记一下,
再从S开始走,不过这回不走上面标记过的边(不是点),
走完以后,所有访问过的点会与上面标记的路径上的点有部分重合,
我们发现,重合的点中,最右边的(也就是路径中靠后的)设为X,那么,S~X这条路径上的边都不是桥边,反而,在标记的路径上,X的出边一定是桥边,
那么,这样就求出了离S最近的桥边,下一个就从X在路径中的下一个点开始做,
这样就可以找出全部桥边了;
Code
void dfsf(int q)
{
z[q]=TI;D[++D[0]]=q;No[q]=D[0];
if(q==T){OK=1;return;}
efo(i,q)if(z[B[i][1]]<TI)
{
B[i][3]=1;D1[D[0]]=i;
dfsf(B[i][1]);
if(OK)return;
B[i][3]=1;
}
D[0]--;No[q]=0;
}
void dfs(int q,int G,int LM)
{
z[q]=TI;g[q]=G;
if(No[NS]<No[q])NS=q;
efo(i,q)if(B[i][3]<LM&&z[B[i][1]]<TI)dfs(B[i][1],G,LM);
}
int main()
{
OK=0;D[0]=0;TI++;dfsf(S);
if(!OK){printf("-1\n");continue;}
TI++;D[0]=1;
for(q=S;q!=T;D[++D[0]]=q=B[D1[No[NS]]][1],D1[D[0]-1]=D1[No[NS]])
{
NS=0;
dfs(q,q,1);
if(NS==T)break;
}
}
Solution2
先按拓扑排序排序所有点,
统计出S到T的方案数,
有结论:如果这条边是桥边,那么这条边两边的点x、y也是必经点,而且S到x的方案数*y到T的方案数=S到T的方案数,这个是充分必要的。
必经点同理;
Solution3
这里用到了支配树,且只能用来求必经点,不能求桥边;
支配树:每个点在树上表示从S出发到它,离它最近的必经点,
支配树在DAG上很好做,先排拓扑序,
那么,点x在支配树上的父亲就是所有能走到它的点在支配树上的LCA(这个感性理解),
这样就可以在
O(nlog(n))
的时间里求解,而且还是多个点的;