在许多题目中,常常都需要一下操作:给出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))
的时间里求解,而且还是多个点的;