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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值