zoukankan      html  css  js  c++  java
  • 由最小环问题想到的

    由于图论的算法不太熟悉,今天早上考了一道NOIP原题打爆了。。所以我要好好学下最小环。。

    最小环的算法有并查集、trajan、反图。这里从简单的开始写

    反图:设G为原图,F图为反图。

    step1:对G遍历记录每个点的退出顺序dfn[]

    对于下面这个图遍历序列为1 2 3 5 (5 3 2 )1 3(4 1)

    括号括起来的是返回值

    dfn=5 3 2 4 1

    G图

    step2:对反图F 按照dfn的反序对反图进行dfs遍历

    访问过程:1 4 (return)2 5 3 (return)

    F图如下:

    得出两个强联通分量就是14 ; 2 5 3; 

    在最小环处理的问题上要注意两个问题

    1.图的强联通问题:必须保证图的联通性如果不行,那么反复dfs知道找到所有点为止

    2.单个的点不是环及dfs2中得出cnt=1的情况要舍去

    程序:

    # include <cstdio>
    # include <cstring>
    # include <iostream>
    using namespace std;
    struct rec{
        int pre,to;
    };
    const int MAXN=1000005;
    int n,m,tot1=0,tot2=0;
    int dfn[MAXN],head1[MAXN],head2[MAXN];
    bool vis[MAXN];
    rec a[MAXN],b[MAXN];
    int adde1(int u,int v) //正图前向星
    {
        tot1++;
        a[tot1].pre=head1[u];
        a[tot1].to=v;
        head1[u]=tot1;
    }
    int adde2(int u,int v)//反图前向星
    {
        tot2++;
        b[tot2].pre=head2[u];
        b[tot2].to=v;
        head2[u]=tot2;
    }
    int dfs1(int u) //求dfn序
    {
        vis[u]=true;
        for (int i=head1[u];i!=0;i=a[i].pre)
         {
             int v=a[i].to;
             if (vis[v]==true) continue;
             dfs1(v);
         }
         dfn[++dfn[0]]=u;
    }
    int dfs2(int u) //求环
    {
        vis[u]=true;
        for (int i=head2[u];i!=0;i=b[i].pre)
        {
            int v=b[i].to;
            if (vis[v]==true) continue;
            dfs2(v);
        }
        printf("%d ",u);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int u,v; 
            scanf("%d%d",&u,&v);
            adde1(u,v); adde2(v,u);//正图A,反图B;
        }
        memset(dfn,0,sizeof(dfn));
        memset(vis,false,sizeof(vis));
        for (int i=1;i<=n;i++)
         if (vis[i]==false) dfs1(i); //得出dfn
        /* 
        printf("*****************************************************
    ");
        printf("调试输出dfn[]:  ");
        
        for (int i=1;i<=dfn[0];i++) printf("%d ",dfn[i]);
        for (int i=1;i<=first[0];i++) printf("%d ",first[i]);
        printf("
    ");
        printf("*****************************************************
    ");
        */
        memset(vis,false,sizeof(vis));
        int cnt=0;
        for (int i=dfn[0];i>0;i--) //反序搞一搞求强联通块
        {
            if (vis[dfn[i]]==true) continue;
            cnt++;
            printf("强联通块# %d  :",cnt);
            dfs2(dfn[i]); printf("
    ");
        }
        return 0;
    }

     上述代码就可以求一个图中最小环的个数复杂度是O(2*n)应该来说比较快,这里放道模板题目:

     P2661 信息传递 (NOIP2015D1T2)

    AC记录:https://www.luogu.org/record/show?rid=8851604

  • 相关阅读:
    sopt:一个简单的python最优化库
    条件GAN论文简单解读
    python PIL 图像处理库简介(一)
    python自动制作gif并添加文字
    github+hexo搭建博客
    haskell简明入门(一)
    DCGAN 代码简单解读
    手机浏览器 H5直播
    js获取网页的宽高
    vue 对象赋值 对象身上已经有了属性,但是视图层并没有更新该数据 问题
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/9359951.html
Copyright © 2011-2022 走看看