算法导论-第22章-基本的图算法-22.5 强连通分量

来源:互联网 发布:php的转义字符有哪些 编辑:程序博客网 时间:2024/05/22 23:22

转自

#include <iostream>using namespace std;//8个点#define N 8 #define WHITE 0#define GRAY 1#define BLACK 2//边结点结构struct Edge{    int start;//有向图的起点    int end;//有向图的终点    Edge *next;//指向同一个起点的下一条边    int type;//边的类型    Edge(int s, int e):start(s),end(e),next(NULL){}};//顶点结点结构struct Vertex{    int id;    Edge *head;//指向以该顶点为起点的下一条边    int color;//顶点的颜色    Vertex *p;//指向遍历结果的父结点    int d, f;//第一次被发现的时间和结束检查的时间    Vertex( ):head(NULL),color(WHITE),p(NULL),d(0x7fffffff),id(0){}};//图结构struct Graph{    Vertex V[N+1];//N个顶点    Graph()    {        int i;        for(i = 1; i <= N; i++)            V[i].id=i;    }};int time = 0;bool flag = 0;//flag为0表示第一次调用DFS,为1表示第二次调用DFSint Sort[N+1] = {N};//存储按u.f从大到小排序时的点,即sort[1]存储的点的f值最大,sort[N]存储的点的f值最小,按这个点的顺序调用DFS_Visit函数//插入边,按边的end由小到大排列void InsertEdge(Graph *G, int start , int end){    Edge *E = new Edge(start,end);    //如果当前点E->start的链表为空,则把E边作为head    if(G->V[E->start].head == NULL)        G->V[E->start].head =E;    //如果有,加入到链表中,递增顺序排列,便于查重    else    {        //链表的插入        Edge *e1 = G->V[E->start].head, *e2 = e1;        while(e1 && e1->end < E->end)        {            e2 = e1;            e1 = e1->next;        }        //插入了重复的边,直接返回        if(e1 && e1->end == E->end)            return;        //第一条边的end都比E边的end大, 此时e1 == e2,则把E作为head        if(e1 == e2)        {            E->next = e1;            G->V[E->start].head =E;        }        //找到E的正确位置        else        {            e2->next = E;            E->next = e1;        }    }}//转置,重新构造一个图Graph* Reverse(Graph *G)  {      Graph *ret = new Graph;      int i;      //遍历图G中的每一条边,以终点为起点,以起点为终点,加入到新图RET中       for(i = 1; i <= N; i++)      {          Edge *E = G->V[i].head;          while(E)          {               InsertEdge(ret, E->end, E->start);              E = E->next;          }      }      return ret;  }//访问某顶点void DFS_Visit(Graph *G, Vertex *u){    //在第二次DFS调用时输出    if(flag)        cout<<u->id<<' ';    //将u置为黑色    u->color = GRAY;    //使全局变量time增值    time++;    //将time的新值记录为发现时间    u->d = time;    //检查和u相邻的每个顶点v    Vertex *v;    Edge *e = u->head;    while(e)    {        v = &G->V[e->end];        //如果顶点为白色        if(v->color == WHITE)        {            //递归访问顶点            v->p = u;            DFS_Visit(G, v);            //树边            e->type = 1;        }        else if(v->color == GRAY)        {            //反向边            e->type = 2;        }        else if(v->color == BLACK)        {            //正向边            if(u->d < v->d)                e->type = 3;            //交叉边            else                e->type = 4;        }        e = e->next;    }    //以u为起点的所有边都被探寻后,置u为黑色    u->color = BLACK;    //并将完成时间记录在f[u]中    time++;    u->f = time;    //把结果按照f从大到小的顺序保存于Sort数组中    if(flag == 0)    {        Sort[Sort[0]] = u->id;        Sort[0]--;    }}//深度优先搜索void DFS(Graph *G){    int i;    //对每个顶点初始化    for(i = 1; i <= N; i++)    {        G->V[i].id = i;        G->V[i].color = WHITE;        G->V[i].p = NULL;    }    //时间戳初始化    time = 0;    //依次检索V中的顶点,发现白色顶点时,调用DFS_Visit访问该顶点    for(i = 1; i <= N; i++)    {        int j;        //第一次是以正常顺序按点1->2->3->.....->8的顺序调用DFS_Visit函数        if(flag == 0)            j = i;        //第二次是以f从大到小的顺序,这个顺序在第一次dfs次保存于Sort数组中        else             j = Sort[i];        //发现白色顶点时,调用DFS_Visit访问该顶点        if(G->V[j].color == WHITE)        {            if(flag)                cout<<"强连通分量为:";            DFS_Visit(G, &G->V[j]);            //flag == 1时,第二次调用DFS,此时每次调用DFS_Visit 就会输出一个强连通分量,换行后,再调用,又输出一个强连通分量            if(flag)                cout<<endl;        }    }}void Strongly_Connected_Component(Graph *G){    //第一次DFS,计算每个顶点的f    DFS(G);    //转置,计算GT       Graph *G2 = Reverse(G);      //第一次的DFS和第二次的DFS不同,用flag区分    flag = 1;    //第二次的DFS,按照f从大到小的顺序调用    DFS(G2);}/*  1  →2→ 3 ↔ 4↓↑ ↙↓  ↓  ↓  5 → 6 ↔ 7 →8  上面8还要指向自己,共15条边*/int main()  {      //构造一个空的图       Graph *G = new Graph;       //15条边    int edge[16][2] = {{0,0},{1,2},{1,5},{2,3},{2,5},{2,6},{3,4},{3,7},{4,3},{4,8},{5,1},{5,6},{6,7},{7,6},{7,8},{8,8}};    for(int i = 1; i <= 15; i++)      {               int start = edge[i][0];        int end = edge[i][1];          InsertEdge(G, start , end);         }      //计算强联通分量    Strongly_Connected_Component(G);    return 0;  }  
阅读全文
0 0