(1)如何判断一个图是不是含有环?
a. DFS,出现返回边则有环。
b. 拓扑排序,若所有的顶点都出现在拓扑排序中,则不出现环。
(2)拓扑排序
a.什么是偏序,全序?from:
http://www.programfan.com/club/showbbs.asp?id=221968
偏序是由实数中的 >= 和 <= 抽象出来的 在一个集合F中定义一个比较关系,这个关系不要求任意两个元素都能比较 这个关系可以任意定义,记为 < ,但是定义的关系要满足以下3个条件 1 )任意a属于F,有a < a;...说明元素自己可以和自己比较 2 )如果a和b能比较且a < b,b和c能比较,且b < c 那么a和c就能比较,且a < c...说明比较关系具有传递性 3 )如果a和b能比较,且a < b,b < a,那么a = b 定义的这种满足以上3条公理的比较关系就叫偏序,和所在的集合记为(F, < ) 全序首先是偏序,但是比偏序多一个要求:集合中的任意两个元素都是可比的。
b.拓扑排序:
由偏序定义得到拓扑有序的操作便是拓扑排序(topological order)。
算法:
(1) 在有向图中选一个没有前驱的顶点输出。
(2) 从图中删除该定点和所有以它为尾的弧。
(3) 重复前两步,直至所有节点都输出,或当前图中不存在无前驱的节点(存在环)。
图采用邻接表实现,头文件代码如下:
#define MAX_VERTEX_NUM20 typedefint InfoType; typedef char VertexType; typedef enum ... {DG,DN,UDG,UDN} GraphKind; typedef struct ArcNode ... { int adjvex; struct ArcNode * next; InfoTypeinfo; } ArcNode; typedef struct VNode ... { int in_degree; VertexTypedata; ArcNode * firstarc; } VNode,AdjList[MAX_VERTEX_NUM]; typedef struct ... { AdjListvertex; int vexnum,arcnum; GraphKindkind; } algraph;
源文件代码:
#include " algraph_topo.h " #include" stdio.h " #include" stdlib.h " void createDN(algraph & g) ... {} void createUDN(algraph & g) ... {} void createUDG(algraph & g) ... {} // locatethenamevertice'sindex int locate(algraphg, char name) ... { for ( int i = 0 ;i < g.vexnum;i ++ ) ... { if (name == g.vertex[i].data) ... { return i; } }return - 1 ; } void createDG(algraph & g) ... { printf( " inputthenumberofvertexandarcs: " ); scanf( " %d%d " , & g.vexnum, & g.arcnum); fflush(stdin); int i = 0 ,j = 0 ,k = 0 ; printf( " inputthenameofvertex: " ); for (i = 0 ;i < g.vexnum;i ++ ) ... { scanf( " %c " , & g.vertex[i].data); fflush(stdin); g.vertex[i].firstarc = NULL; g.vertex[i].in_degree = 0 ; } // constructtheadjacentlist char v1,v2; int w; ArcNode * p; printf( " inputthe%darcsv1v2andweight: " ,g.arcnum); for (k = 0 ;k < g.arcnum;k ++ ) ... { scanf( " %c%c%d " , & v1, & v2, & w); fflush(stdin); i = locate(g,v1); j = locate(g,v2); // newanode p = (ArcNode * )malloc( sizeof (ArcNode)); p -> adjvex = j; p -> info = w; p -> next = NULL; // insertthenodeintheheadoflist if ( ! g.vertex[i].firstarc) ... { g.vertex[i].firstarc = p; } else ... { p -> next = g.vertex[i].firstarc; g.vertex[i].firstarc = p; } g.vertex[j].in_degree++ ; } }// printthelist void printGraph(algraphg) ... { for ( int i = 0 ;i < g.vexnum;i ++ ) ... { printf( " %c'sadjacentlistis: " ,g.vertex[i].data); ArcNode * p = g.vertex[i].firstarc; while (p) ... { printf( " %c(%d) " ,g.vertex[p -> adjvex].data,p -> info); p = p -> next; } printf(" " ); } }void createGragh(algraph & g) ... { printf( " pleaseinputthetypeofgraph: " ); scanf( " %d " , & g.kind); switch (g.kind) ... { case DG: createDG(g); // printGraph(g); break ; case DN: createDN(g); break ; case UDG: createUDG(g); break ; case UDN: createUDN(g); break ; } }// ²éÕÒÏÂÒ»¸ö int findNext(algraphg) ... { for ( int i = 0 ;i < g.vexnum;i ++ ) ... { if (g.vertex[i].in_degree == 0 ) ... { return i; } }return - 1 ; } // topoorder void topoSort(algraphg) ... { printf( " thetoposortofgraphis: " ); for ( int i = 0 ;i < g.vexnum;i ++ ) ... { int index = findNext(g); if (index > - 1 ) ... { printf( " %c " ,g.vertex[index].data); // don'tconsidertheverticeagain g.vertex[index].in_degree = - 1 ; ArcNode * p = g.vertex[index].firstarc; while (p) ... { g.vertex[p -> adjvex].in_degree -- ; p = p -> next; } }else ... { break ; } } printf(" " ); } void main() ... { algraphg; createGragh(g); topoSort(g); }
程序的运行结果如下:
pleaseinputthetypeofgraph: 0 inputthenumberofvertexandarcs:6 8 inputthenameofvertex: a b c d e f inputthe8 arcsv1v2andweight: ad 1 ac1 ab1 ce1 cb1 de1 fe1 fd1 thetoposortofgraphis : acbfde Pressanykeyto continue
说明:
(1) 为了避免重复检测入度为0的顶点,可设置一个栈暂存所有入度为0的顶点,复杂度为O(n + e)。而在程序中采用的是
// don'tconsidertheverticeagain g.vertex[index].in_degree = - 1 ;
来实现的。复杂度要高一些。
(2) 可以使用DFS,退出DFS函数的顺序即为逆向的拓扑有序序列。
(3)关键路径
a. AOV网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网(activity on vertex network)。AOV网中,没有有向环。
b. AOE网:边表示活动的网络(顶点表示事件,弧表示活动),用来估算工程的完成时间,通常只有一个源点和一个汇点。
c. 求AOE算法的复杂度是O(n + e)