现在的位置: 首页 > 综合 > 正文

tarjan算法求有向图的强连通分量(邻接矩阵实现)

2017年10月18日 ⁄ 综合 ⁄ 共 1622字 ⁄ 字号 评论关闭

         这个是个最简单的实现tarjan算法的程序了,主要是为了了解这个算法,以及中间的过程,

        因为邻接矩阵写的话,简单明了,适用于理解算法。当然对邻接表,节点是单一一个数字或字符的,实现也比较简单

        改天我会再写个用邻接表的,节点是字符串的。那样的话,程序更具有广泛性。使用范围就更广了。

        这里的节点字符单一,对于是字符串的节点的图的话,明显不具有解答能力。

        可以用一种方法,对字符串标序,并且字符串与序号绑定起来。我有一篇文章就是讲用这个方法实现DFS和BFS,节点为字符串的的程序

        tarjan算法的步骤:

step  1:对图中的点深搜,

          2:在深搜过程中,对每个节点进行标记,也就是记起来这个节点是第几个搜到的

          3:判断每个点它能通过回边所到达的标记序号最小的点,然后在回溯时对每个节点进行一次比较,存下标记序号最小的

         4:如果标记序号和它所能搜到的序号最小的点的那个序号相等,那么就将栈里在它上面的节点全部输出,它自己也输出,也都退栈。

         5: 继续回溯,深搜。

 

下面贴一下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100
int map[N][N];//存入图,这里是用邻接矩阵,
//假如要用邻接表的话,如果节点也是单一的一个数字,也蛮简单,
//这里就不写了,如果有时间我再写个邻接表的,节点是字符串的来
int dist[N];//这个就是标记数组,表示此时这个节点是否在栈中
int dfn[N],low[N];//第一个是存搜索顺序的数组,
//第二个是存此时这个点所能到达搜索顺序最小的节点的dfn,即那点的序号
int z[N];//这里是用这个数组模拟栈
int n,m,t=0,top=-1;//n表示节点的个数,m表示边的数量,t是用来初始化dfn,和low的
//top就是代表栈顶

void init()//初始化
{
    int i, j, r;
    memset(map,-1,sizeof(map));
    memset(dist,0,sizeof(dist));
    memset(dfn,0,sizeof(dfn));
    for(j=1; j<=m; j++)//输入边
    {
        scanf("%d%d",&i,&r);
        map[i][r]=1;
    }
}

void tarjan(int k)//tarjan算法的实现,
{
    int i;
    dfn[k]=low[k]=++t;//标记搜索序号,并将low也赋同样的值
    z[++top]=k;//将k入栈
    dist[k]=1;//标记k已在栈中
    for(i=1; i<=n; i++)//dfs
    {
        if(map[k][i]!=-1)
        {
            if(dfn[i]==0)//i没入栈,这里其实也可以改为dist[i]==0,效果是一样的
            {//dfn的话因为在经过tarjan里会被赋值,所以就不会为0,没经过的话就代表没搜过
                tarjan(i);//那么就要搜它
                if(low[k]>low[i])low[k]=low[i];//将所能达到的最小的搜索序赋给low[k]
            }
            else if(dist[i]==1&&low[k]>dfn[i])//如果在栈中,就直接比较,存最小
            {
                low[k]=dfn[i];
            }
        }
    }
    if(low[k]==dfn[k])//如果相等那么就要输出这一个强连通分量
    {
        do
        {
            printf("%d ",z[top]);
            dist[z[top]]=0;
        }
        while(z[top--]!=k);
        printf("\n");
    }
    return ;
}

int main()
{
    int i;
    scanf("%d %d",&m,&n);
    init();
    for(i=1; i<=n; i++)
        if(!dfn[i])//没有经过tarjan搜索过
            tarjan(i);//那么就搜它
    return 0;
}

 

抱歉!评论已关闭.