zoukankan      html  css  js  c++  java
  • CF521E

    CF521E

    给定一张 n 个点 m 条边的无向简单图。

    问图中能否找到两个点,满足这两个点之间有至少三条完全不相交的简单路径。

    n,m ≤ 2 × 1e5,图不保证连通。

    =======================================================

    两点间有三条完全不相交路径,可将问题转化为
    两个环有边相交,再转换一下
    一棵树上的一条树边被两条非树边覆盖
    即,在下面的图中,树边 d -> lca 被两条非树边覆盖,这样就找到了三条路径

    1、树上的那条路径,即 d -> lca

    2、d -> b -> a -> p

    3、d -> c -> p

    code

    int v[N],ins[N];
    int cx[N],cy[N];
    //cx,cy表示被那条边覆盖了
    //下面的程序中,cy 是较浅的那个 
     
    int lca(int x,int y)//如此暴力的 lca 我还是第一次写 
    {
        while(dep[x] > dep[y]) x = fa[x];
        while(dep[x] < dep[y]) y = fa[y];
        while(x != y) x = fa[x],y = fa[y];
        return x;
    }
     
    int tmp[N];
    int tp;
    //来记录答案的路径 
    void add_path(int x,int y)
    {
        while(x != y)
        {
            tmp[++ tp] = x;
            x = fa[x];
        }
        tmp[++ tp] = y;
    }
     
    void ccout()
    {
        cout << tp << " ";
        for(int i = 1;i <= tp;i ++)
            cout << tmp[i] << ' ';
        cout << endl;
        tp = 0;//将路径清空,准备下一次记录 
    }
     
    void get(int a,int b,int c,int d)
    {
        if(dep[b] > dep[d]) swap(a,c),swap(b,d);
        //现在的话,就是,ab深度较小,cd较深
        int p = lca(a,c);
         
        puts("YES");
         
        add_path(p,d);//1、树上的那条路径
        reverse(tmp + 1,tmp + 1 + tp);
        //将路径顺序颠倒,从浅的开始输出
        ccout();
         
        add_path(d,b);//2、d -> b -> a -> p 的这条路径 
        add_path(a,p);
        ccout();
         
        tmp[++ tp] = d;//3、 d -> c -> p 的那条路径 
        add_path(c,p);
        ccout();
         
        exit(0);//结束程序 
    }
     
    void dfs(int x)
    {
        v[x] = 1;//当前点已被遍历
        ins[x] = 1;//标记当前点,在回溯的时候取消标记
        for(int i = head[x];i;i = nxt[i])
        {
            int y = to[i];
            if(y == fa[x]) continue; 
            if(!v[y])
            {
                dep[y] = dep[x] + 1;
                fa[y] = x;
                dfs(y);
            }
            else if(ins[y])//我们这时候发现有一个被标记的点,也就是我们发现了一个环
                for(int u = x;u != y;u = fa[u])//注意 :现在的 y 才是深度较浅的那个 
                    if(cx[u] && cy[u]) get(cx[u],cy[u],x,y);//既然已经被覆盖过了,当前这次就是第二次覆盖了,可以结束了 
                    else cx[u] = x,cy[u] = y;//没有被覆盖过 ,标记一下这个环被 x ,y 覆盖 
        }
        ins[x] = 0;//回溯了 
    }
    

    思路和图片来自这里,我整理了代码的注释部分,如有问题请联系作者

  • 相关阅读:
    微信表情代码
    SQL四个排名函数(row_number、rank、dense_rank和ntile)的使用
    JS获取URL传过来的参数
    QQ在线咨询代码
    AJAX定时请求数据
    C#模拟登录主动推送信息
    HTML 5实现手机摇一摇的功能
    禁用站点asp运行
    二维码扫描极速版4.0.apk
    .NET Framework4网站 无法运行,提示找不到网络名,IO错误等解决办法
  • 原文地址:https://www.cnblogs.com/xy0313/p/14072892.html
Copyright © 2011-2022 走看看