#include <stdio.h>
#include <stdlib.h>
#define WHITE 0
#define GRAY 1
#define BLACK 2
//CNT用于编号TOPO序列,CNT_GROUP用于编号group
int CNT,CNT_GROUP;
//顶点类型,f是算导标准算法中的一个属性,这里其实可以省略
typedef struct
{
int color;
int group;
char name;
int f;
}Vertex,*pVertex;
//图类型,包含Topo排序数组
typedef struct
{
int v_n;
pVertex *V;
int **E;
int *TopoOrder;
}Graph,*pGraph;
//根据算导中的图22-9进行初始化
pGraph initGraph()
{
pGraph g = (pGraph)malloc(sizeof(Graph));
g->v_n=8;
g->TopoOrder=(int*)malloc(g->v_n*sizeof(int));
pVertex v1=(pVertex)malloc(sizeof(Vertex));
v1->name='a';
v1->group=-1;
v1->color=WHITE;
v1->f=0;
pVertex v2=(pVertex)malloc(sizeof(Vertex));
v2->name='b';
v2->group=-1;
v2->color=WHITE;
v2->f=0;
pVertex v3=(pVertex)malloc(sizeof(Vertex));
v3->name='c';
v3->group=-1;
v3->color=WHITE;
v3->f=0;
pVertex v4=(pVertex)malloc(sizeof(Vertex));
v4->name='d';
v4->group=-1;
v4->color=WHITE;
v4->f=0;
pVertex v5=(pVertex)malloc(sizeof(Vertex));
v5->name='e';
v5->group=-1;
v5->color=WHITE;
v5->f=0;
pVertex v6=(pVertex)malloc(sizeof(Vertex));
v6->name='f';
v6->group=-1;
v6->color=WHITE;
v6->f=0;
pVertex v7=(pVertex)malloc(sizeof(Vertex));
v7->name='g';
v7->group=-1;
v7->color=WHITE;
v7->f=0;
pVertex v8=(pVertex)malloc(sizeof(Vertex));
v8->name='h';
v8->group=-1;
v8->color=WHITE;
v8->f=0;
g->V = (pVertex *)malloc(g->v_n*sizeof(Vertex));
g->V[0]=v1;
g->V[1]=v2;
g->V[2]=v3;
g->V[3]=v4;
g->V[4]=v5;
g->V[5]=v6;
g->V[6]=v7;
g->V[7]=v8;
g->E=(int**)malloc(g->v_n*sizeof(int*));
for(int i=0;i<g->v_n;i++)
{
g->E[i]=(int*)malloc(g->v_n*sizeof(int));
}
for(int i=0;i<g->v_n;i++)
{
for(int j=0;j<g->v_n;j++)
{
g->E[i][j]=0;
}
}
g->E[0][1]=1;
g->E[1][2]=1;
g->E[1][4]=1;
g->E[1][5]=1;
g->E[2][3]=1;
g->E[2][6]=1;
g->E[3][2]=1;
g->E[3][7]=1;
g->E[4][0]=1;
g->E[4][5]=1;
g->E[5][6]=1;
g->E[6][5]=1;
g->E[6][7]=1;
g->E[7][7]=1;
return g;
}
//矩阵转置,除了取反向边,其余全部复制
pGraph transposeGraph(pGraph x)
{
pGraph g = (pGraph)malloc(sizeof(Graph));
g->v_n=x->v_n;
g->TopoOrder=(int*)malloc(g->v_n*sizeof(int));
g->V = (pVertex *)malloc(g->v_n*sizeof(Vertex));
for(int i=0;i<g->v_n;i++)
{
pVertex v=(pVertex)malloc(sizeof(Vertex));
v->color=x->V[i]->color;
v->group=x->V[i]->group;
v->name=x->V[i]->name;
v->f=x->V[i]->f;
g->V[i]=v;
}
for(int i=0;i<g->v_n;i++)
{
g->TopoOrder[i]=x->TopoOrder[i];
}
g->E=(int**)malloc(g->v_n*sizeof(int*));
for(int i=0;i<g->v_n;i++)
{
g->E[i]=(int*)malloc(g->v_n*sizeof(int));
}
for(int i=0;i<g->v_n;i++)
{
for(int j=0;j<g->v_n;j++)
{
if(x->E[i][j]==1)
g->E[j][i]=1;
else
g->E[j][i]=0;
}
}
return g;
}
void dfsVisit(pGraph g,int v)
{
g->V[v]->color=GRAY;
for(int i=0;i<g->v_n;i++)
{
if(g->E[v][i]==1)
{
if(g->V[i]->color==WHITE)
dfsVisit(g,i);
}
}
g->V[v]->color=BLACK;
g->V[v]->f=CNT;
g->TopoOrder[CNT]=v;
CNT++;
}
void dfs(pGraph g)
{
for(int i=0;i<g->v_n;i++)
{
g->V[i]->color=WHITE;
}
CNT=CNT_GROUP=0;
for(int i=0;i<g->v_n;i++)
{
if(g->V[i]->color==WHITE)
dfsVisit(g,i);
}
}
void dfsVisit2(pGraph g,int v)
{
g->V[v]->color=GRAY;
for(int i=0;i<g->v_n;i++)
{
if(g->E[v][i]==1)
{
if(g->V[i]->color==WHITE)
dfsVisit2(g,i);
}
}
g->V[v]->color=BLACK;
g->V[v]->f=CNT;
g->V[v]->group=CNT_GROUP;
CNT++;
}
void dfs2(pGraph g)
{
for(int i=0;i<g->v_n;i++)
{
g->V[i]->color=WHITE;
}
CNT=CNT_GROUP=0;
for(int i=g->v_n-1;i>=0;i--)
{
int j=g->TopoOrder[i];
if(g->V[j]->color==WHITE)
{
dfsVisit2(g,j);
CNT_GROUP++;
}
}
}
void printGroup(pGraph g)
{
for(int i=0;i<g->v_n;i++)
{
printf("%c:%d,",g->V[i]->name,g->V[i]->group);
}
printf("\n");
}
void printTopo(pGraph g)
{
for(int i=g->v_n-1;i>=0;i--)
{
int j=g->TopoOrder[i];
printf("%c:%d,",g->V[j]->name,i);
}
printf("\n");
}
void printE(pGraph g)
{
for(int i=0;i<g->v_n;i++)
{
for(int j=0;j<g->v_n;j++)
{
printf("%d ",g->E[i][j]);
}
printf("\n");
}
}
//分两遍DFS,第一遍取得原图Topo序列,第二遍根据Topo序列遍历顶点,取得强连通分量
//为什么两遍可以取得强连通分量,请参考http://blog.sina.com.cn/s/blog_4dff87120100r58c.html
void main()
{
pGraph g=initGraph();
dfs(g);
//printE(g);
printTopo(g);
pGraph gt=transposeGraph(g);
dfs2(gt);
//printE(gt);
printGroup(gt);
getchar();
}
算法导论 强连通分量
最新推荐文章于 2024-09-09 19:25:47 发布