p357强连通分量

书上的这个算法叫做kosaraju算法

  • 首先做一次dfs
  • 计算图的转置
  • 在转置图上按照第一次dfs完成时间f递减的顺序再进行一次dfs
    前两个步骤很直白,关键是第3步,要按递减的顺序嘛,于是我就想排序,拍完后发现不对,由于点在g数组的位置发生了变化,整个图的结构完全被打乱了→_→;其实我忽略了dfs非常重要的性质——这不是有一个时间戳嘛?节点探索完成的顺序就是f递增的顺序,放到头插法创建的链表里面就变成了递减的顺序(好吧这其实就是拓扑排序,不过这里的图G可以是有环图)

写这段代码的感受

  • 开始写代码之前思路一定要清晰,明白每一步会产生什么后果,如果自己都不明白,那计算机咋办呢?
  • 慎用指针,一开始link里面存的不是节点号,是指向图G里面g中某个点的指针,这样一来,dfs2再对link里面的节点进行操作,相当于还是对G而不是Gt进行操作,指来指去的指针呵^-^
#include<stdio.h>
#include<stdlib.h>
#define white 1
#define gray 2
#define black 3
typedef struct edge{
    int i;//节点号
    struct edge *next;
}edge;
typedef struct node{
    int i/*节点号*/,d,f,color;
    edge *next;
}node;
typedef struct gve{
    int v,e;
    node *g;/*点的数组*/
}gve;
typedef struct link_element{
    int i;/*节点号*/
    struct link_element *next;
}link_element;
int insert(node *pnode,int i)
{
    edge *new;
    new=(edge *)malloc(sizeof(edge));
    new->i=i;
    new->next=pnode->next;
    pnode->next=new;
    return 0;
}
int link_insert(link_element **link,int i)/*头插法,使节点按照从头到尾按f递减的顺序排列*/
{
    link_element *new;
    new=(link_element *)malloc(sizeof(link_element));
    new->i=i;
    new->next=*link;
    *link=new;
    return 0;
}
int dfsvisit(gve G,node *pnode,int *time,link_element **link)/*进行第一遍深搜,并产生节点的按f递减排列的链表*/
{
    edge *tmp=pnode->next;
    (*time)++;
    pnode->d=*time;
    pnode->color=gray;
    while (tmp!=NULL)
    {
        if (G.g[tmp->i].color==white)
            dfsvisit(G,&G.g[tmp->i],time,link);
        tmp=tmp->next;
    }
    pnode->color=black;
    (*time)++;
    pnode->f=*time;
    link_insert(link,pnode->i);/*一完成探索就加入链表*/
    return 0;
}
int dfs(gve G,link_element **link)/*进行第一遍深搜,并产生节点的按f递减排列的链表*/
{
    int time=0,i;
    for (i=1;i<=G.v;i++)
        if (G.g[i].color==white)
            dfsvisit(G,&G.g[i],&time,link);
    return 0;
}
int dfsvisit2(gve G,node *pnode,int *time)/*以某个节点为根深搜,和原版dfsvisit一样*/
{
    edge *tmp=pnode->next;
    (*time)++;
    pnode->d=*time;
    pnode->color=gray;
    printf("%d ",pnode->i);/*树中每个节点都是根所在强连通分量的节点,根所在强连通分量的节点也都是树中的每个节点,这点在359页有证明*/
    while (tmp!=NULL)
    {
        if (G.g[tmp->i].color==white)
            dfsvisit2(G,&G.g[tmp->i],time);
        tmp=tmp->next;
    }
    pnode->color=black;
    (*time)++;
    pnode->f=*time;
    return 0;
}
int dfs2(gve G,link_element **link)/*以第一步产生的link为顺序对转置图进行深搜*/
{
    int time=0;
    link_element *tmp=*link;
    while (tmp!=NULL)
    {
        if (G.g[tmp->i].color==white)
        {
            dfsvisit2(G,&G.g[tmp->i],&time);
            printf("\n");
        }
        tmp=tmp->next;
    }
    return 0;
}
gve trans(gve G)/*计算图的转置,不需要保留原图的d和f,只要把颜色置为white,边反向即可*/
{
    gve Gt;
    Gt.v=G.v;
    Gt.e=G.e;
    Gt.g=(node *)malloc(sizeof(node)*(Gt.v+1));
    int i;
    for (i=1;i<=Gt.v;i++)
    {
        Gt.g[i].next=NULL;
        Gt.g[i].color=white;
        Gt.g[i].i=i;
    }
    edge *tmp;
    for (i=1;i<=Gt.v;i++)
    {
        tmp=G.g[i].next;
        while (tmp!=NULL)
        {
            insert(&Gt.g[tmp->i],i);
            tmp=tmp->next;
        }
    }
    return Gt;
}
int css(gve G)/*计算强连通分量*/
{
    link_element **link;
    link=(link_element **)malloc(sizeof(link_element *));
    *link=NULL;
    gve Gt;
    dfs(G,link);
    Gt=trans(G);
    dfs2(Gt,link);
    return 0;
}
int main(void)
{
    int i;
    gve G;
    scanf("%d%d",&G.v,&G.e);
    G.g=(node *)malloc(sizeof(node)*(G.v+1));
    for (i=1;i<=G.v;i++)
    {
        G.g[i].next=NULL;
        G.g[i].color=white;
        G.g[i].i=i;
    }
    int s,d;
    for (i=1;i<=G.e;i++)
    {
        scanf("%d%d",&s,&d);
        insert(&G.g[s],d);
    }
    css(G);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值