【数据结构】DFS求有向图的强连通分量

用十字链表结构写的,根据数据结构书上的描述和自己的理解实现。但理解的不透彻,所以不知道有没有错误。但实验了几个都ok.

#include <iostream>
#include <vector>
using namespace std;

//有向图十字链表表示
#define MAX_VERTEX_NUM 20

typedef struct ArcBox{
    int tailvex, headvex; //该弧尾和头顶点的位置
    struct ArcBox *hlink, *tlink; //分别指向弧头相同和弧尾相同的弧的链域
}ArcBox;

typedef struct VexNode{
    int data;
    ArcBox *firstin, *firstout;//分别指向该顶点的第一条入弧和出弧
}VexNode;

typedef struct{
    VexNode xlist[MAX_VERTEX_NUM]; //表头向量
    int vexnum, arcnum; //有向图的顶点数和弧数
}OLGraph;

//定位顶点在xlist中的位置
int LocateVex(OLGraph G, int data)
{
    for(int i = 0; i < G.vexnum; i++)
    {
        if(G.xlist[i].data == data)
        {
            return i;
        }
    }
    cout << "error the vertex "<< data << " is not in the list"<<endl;
    return -1;
}

//有向图十字链表创建
void CreateDG(OLGraph &G)
{
    cout << "please input the number of vertex, the number of arc:";
    cin >> G.vexnum >> G.arcnum;

    for(int i = 0; i < G.vexnum; i++)
    {
        cout << "please input vertex data:";
        cin >> G.xlist[i].data;

        G.xlist[i].firstin = NULL;  //初始化指针
        G.xlist[i].firstout = NULL;
    }

    for(int k = 0; k < G.arcnum; k++)
    {
        int v1, v2; //弧的尾和头
        cout << "please input the tail and head vertex of each tail:";
        cin >> v1 >> v2;

        int i = LocateVex(G, v1);
        int j = LocateVex(G, v2);
        ArcBox * p = new ArcBox;
        p->headvex = j;
        p->tailvex = i;
        p->hlink = G.xlist[j].firstin;
        p->tlink = G.xlist[i].firstout;

        G.xlist[j].firstin = p;
        G.xlist[i].firstout = p;
    }
}

//单向深度优先搜索
//输入: 图G, 开始遍历点v, 遍历标志visited, 遍历方向dir 0 表示从尾向头遍历 1表示从头到尾遍历, vecor存放跳出遍历的顺序
void DFS(OLGraph G, int v, int * visited, int dir, vector<int> * vec)
{
    visited[v] = 1;
    (*vec).push_back(v);
    if(dir == 0) //从尾向头遍历
    {
        ArcBox * w = G.xlist[v].firstout;
        while(w != NULL ) //注意 这里的while
        {
            if(visited[w->headvex] == 1)
            {
                w = w->tlink;
            }
            else//未访问过该点 递归遍历该点
            {
                DFS(G, w->headvex, visited, dir, vec);
                w = w->tlink;
            }
        }
    }
    else //从头向尾遍历
    {
        ArcBox * w = G.xlist[v].firstin;
        while(w != NULL)//查找下一个遍历点
        {
            if((visited[w->tailvex]) == 1)
            {
                w = w->hlink;
            }
            else//未访问过该点 递归遍历该点
            {
                DFS(G, w->tailvex, visited, dir, vec);
                w = w->hlink;
            }
        }
    }
}

//查找有向图强连通分量
vector<vector<int>> FindConnectedPart(OLGraph G)
{
    vector<vector<int>> ConnectedPart;
    vector<vector<int>> finished;
    int* visited = new int[G.vexnum];
    memset(visited, 0, G.vexnum * sizeof(int)); //初始化为全部没有访问过

    //从尾向头遍历
    for(int v = 0; v < G.vexnum; v++)
    {
        if(visited[v] == 0) //没有被访问过
        {
            vector<int> vec;
            DFS(G, v, visited, 0, &vec);
            finished.push_back(vec);
        }
    }

    //从头向尾遍历
    memset(visited, 0, G.vexnum * sizeof(int));
    vector<int>::iterator it;
    vector<vector<int>>::iterator it2;
    int* find = new int[G.vexnum]; //find标识顶点实际上是否被查找过
    for(int i = 0; i < G.vexnum; i++)
    {
        find[i] = 0;
        visited[i] = 1;
    }
    for(it2 = finished.begin(); it2 < finished.end(); it2++)
    {
        //已经遍历过的部分visited不变,即都是1; find[i]= 0的表示本次遍历时不遍历结点i,为了跳过i,设它们的visited[i]=1; 但实际上,它们还没有被访问到
        //比如从尾到头遍历时得到两个分量 (1,2,3,4)(5)
        //那么为了找到重连通分量,从头到尾遍历4,3,2,1时不应该经过5 即可能从头到尾遍历时的分量是(1 2 3 5)(4)
        // 但实际上重连通分量为(1,2,3)(4)(5)三个
        for(it = it2->begin(); it < it2->end(); it++)
        {
            visited[*it] = 0; //只把本次遍历考虑到的顶点的visited设为0,其他为1,就不会加人遍历了
            find[*it] = 1;
        }

        for(it = it2->begin(); it < it2->end(); it++)
        {
            if(visited[*it] == 0) //没有被访问过
            {
                vector<int> vec;
                DFS(G, *it, visited, 1, &vec);
                ConnectedPart.push_back(vec);
            }
        }
    }

    //输出重连通分量
    int n = 0;
    cout << "重连通分量有:" << endl;
    for(it2 = ConnectedPart.begin(); it2 < ConnectedPart.end(); it2++)
    {
        cout << ++n << ":";
        for(it = it2->begin(); it < it2->end(); it++)
        {
            cout << G.xlist[*it].data << " ";
        }
        cout<< endl;
    }

    delete [] visited;
    delete [] find;
    return ConnectedPart;
}

int main()
{
    OLGraph G;
    CreateDG(G);
    FindConnectedPart(G);

    return 0;
}

http://blog.csdn.net/wsniyufang/article/details/6604458里面有将更好的算法。我还没看。

时间: 2024-07-31 07:56:48

【数据结构】DFS求有向图的强连通分量的相关文章

求有向图的强连通分量的算法

下面是求有向图的强连通分量的算法的代码: import java.util.Scanner; class Qiufenliang//定义求强连通分量的类 { String lu="";//定义的一个字符型变量,记录强连通分量的路径 public static int s=0; public void qiu(int a[][],int l)//定义函数,参数a为二维数组,参数l为数组的维数 { int t=0;//定义int型变量,进行数量的统计 for(int i=1;i<l;

求有向图的强连通分量个数 之 Kosaraju算法

代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 int maps[1100][1100],nmap[1100][1100]; 6 int vis[1001]; 7 int ans=0,aaa=0,n,m,post[1100]; 8 void dfs(int); 9 void ndfs(int); 10 int main() 11 { 12 s

图-&gt;连通性-&gt;有向图的强连通分量

文字描述 有向图强连通分量的定义:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 用深度优先搜索求有向图的强连通分量的方法如下并假设有向图的存储结构为十字链表. 1 在有向图G上,从某个定点出发沿以该顶点为尾的弧

DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)

一.dfs框架: 1 vector<int>G[maxn]; //存图 2 int vis[maxn]; //节点访问标记 3 void dfs(int u) 4 { 5 vis[u] = 1; 6 PREVISIT(u); //访问节点u之前的操作 7 int d = G[u].size(); 8 for(int i = 0; i < d; i++)//枚举每条边 9 { 10 int v = G[u][i]; 11 if(!vis[v])dfs(v); 12 } 13 POSTVIS

连通分量 无向图的割顶和桥 无向图的双连通分量 有向图的强连通分量

时间戳 dfs_clock :说白了就是记录下访问每个结点的次序.假设我们用 pre 保存,那么如果 pre[u] > pre[v], 那么就可以知道先访问的 v ,后访问的 u . 现在给定一条边, (u, v), 且 u 的祖先为 fa, 如果有 pre[v] < pre[u] && v != fa, 那么 (u, v) 为一条反向边. 1 求连通分量: 相互可达的节点称为一个连通分量: #include <iostream> #include <cstd

uva11324 有向图的强连通分量+记忆化dp

给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用有向图的强连通分量,进行缩点,然后得到一个有向无环图(DAG) 在采用记忆话dp 去做即可 #include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #inclu

hdu1269 迷宫城堡,有向图的强连通分量 , Tarjan算法

hdu1269 迷宫城堡 验证给出的有向图是不是强连通图... Tarjan算法板子题 Tarjan算法的基础是DFS,对于每个节点.每条边都搜索一次,时间复杂度为O(V+E). 算法步骤: 1.搜索到某一个点时,将该点的Low值标上时间戳,然后将自己作为所在强连通分量的根节点(就是赋值Dfn=Low=time) 2.将该点压入栈. 3.当点p有与点p'相连时,如果此时p'不在栈中,p的low值为两点的low值中较小的一个. 4.当点p有与点p'相连时,如果此时p'在栈中,p的low值为p的lo

poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所

『Tarjan算法 有向图的强连通分量』

有向图的强连通分量 定义:在有向图\(G\)中,如果两个顶点\(v_i,v_j\)间\((v_i>v_j)\)有一条从\(v_i\)到\(v_j\)的有向路径,同时还有一条从\(v_j\)到\(v_i\)的有向路径,则称两个顶点强连通(strongly connected).如果有向图\(G\)的每两个顶点都强连通,称\(G\)是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 万能的Tarjan算法也可以帮助我们求解有向图的强