由最小环问题想到的

由于图论的算法不太熟悉,今天早上考了一道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

原文地址:https://www.cnblogs.com/ljc20020730/p/9359951.html