【DAG】寻找桥边、必经点(支配树)

xiaoxiao2021-02-28  71

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

转载请注明原文地址: https://www.6miu.com/read-66013.html

最新回复(0)