typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
/* 邻接矩阵结构 */
typedef struct
{
int vexs[MAXVEX];
int arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
/* 邻接表结构****************** */
//边表结点
typedef struct EdgeNode
{
//邻接点域,存储该顶点对应的下标
int adjvex;
//用于存储权值,对于非网图可以不需要
int weight;
//链域,指向下一个邻接点
struct EdgeNode *next;
}EdgeNode;
//顶点表结点
typedef struct VertexNode
{
//顶点入度
int in;
//顶点域,存储顶点信息
int data;
//边表头指针
EdgeNode *firstedge;
}VertexNode, AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
//图中当前顶点数和边数
int numVertexes,numEdges;
}graphAdjList,*GraphAdjList;
/* 关于AOE网图的存储代码段-Begin */
//1.完成AOE网图关于邻接矩阵的存储
void CreateMGraph(MGraph *G)/* 构件图 */
{
int i, j;
/* printf("请输入边数和顶点数:"); */
G->numEdges=13;
G->numVertexes=10;
for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
{
G->vexs[i]=i;
}
for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
{
for ( j = 0; j < G->numVertexes; j++)
{
if (i==j)
G->arc[i][j]=0;
else
G->arc[i][j]=INFINITYC;
}
}
G->arc[0][1]=3;
G->arc[0][2]=4;
G->arc[1][3]=5;
G->arc[1][4]=6;
G->arc[2][3]=8;
G->arc[2][5]=7;
G->arc[3][4]=3;
G->arc[4][6]=9;
G->arc[4][7]=4;
G->arc[5][7]=6;
G->arc[6][9]=2;
G->arc[7][8]=5;
G->arc[8][9]=3;
}
//2.将邻近矩阵转化成邻接表
void CreateALGraph(MGraph G,GraphAdjList *GL){
int i,j;
EdgeNode *e;
*GL = (GraphAdjList)malloc(sizeof(graphAdjList));
(*GL)->numVertexes=G.numVertexes;
(*GL)->numEdges=G.numEdges;
//读入顶点信息,建立顶点表
for(i= 0;i <G.numVertexes;i++)
{
(*GL)->adjList[i].in=0;
(*GL)->adjList[i].data=G.vexs[i];
//将边表置为空表
(*GL)->adjList[i].firstedge=NULL;
}
//建立边表
for(i=0;i<G.numVertexes;i++)
{
for(j=0;j<G.numVertexes;j++)
{
if (G.arc[i][j]!=0 && G.arc[i][j]<INFINITYC)
{
e=(EdgeNode *)malloc(sizeof(EdgeNode));
//邻接序号为j
e->adjvex=j;
e->weight=G.arc[i][j];
//将当前顶点上的指向的结点指针赋值给e
e->next=(*GL)->adjList[i].firstedge;
//将当前顶点的指针指向e
(*GL)->adjList[i].firstedge=e;
(*GL)->adjList[j].in++;
}
}
}
}
//
int *etv,*ltv;//事件最早发生的时间和最晚发生的时间
int *stack2;//存储拓扑排序的序列的栈
int top2;//栈stack2的栈顶指针
//拓扑排序
Status TopologicalSort(GraphAdjList GL){
//1.创建一个栈,保存入度为0的顶点下标
int *stack = (int *)malloc(GL->numVertexes*sizeof(int));
int top = 0;//栈stack的栈顶指针
//2.将入度为0的顶点下标入栈
for (int i=0; i<GL->numVertexes; i++) {
if (GL->adjList[i].in == 0) {
stack[++top] = i;
}
}
//3.创建一个栈,保存拓扑排序序列
stack2 = (int *)malloc(GL->numVertexes*sizeof(int));
top2 = 0;//stack2的栈顶指针
//4.创建一个数组,保存顶点事件的最早发生时间
etv = malloc(GL->numVertexes*sizeof(int));
//5.初始化etv
for (int i=0; i<GL->numVertexes; i++) {
etv[i] = 0;
}
printf("TopologicSort:\t");
int gettop;
int count = 0;//计数
EdgeNode *e;
int k;
//6.将stack出栈,并将保存的对应下标的顶点的入度-1,如果-1后入度为0,则入栈stack
while (top !=0 ) {
//拿到栈顶元素
gettop = stack[top--];
printf("%d ->",GL->adjList[gettop].data);
count++;
//将出栈的顶点下标入栈
stack2[++top2] = gettop;
//遍历与顶点gettop相连的所有顶点,将其入度-1
for (e = GL->adjList[gettop].firstedge; e; e = e->next) {
//相连的顶点下标
k = e->adjvex;
if ( (--GL->adjList[k].in) == 0 ) {
//入度为0的顶点下标入栈
stack[++top] = k;
}
//求各顶点事件的最早发生时间etv
if (etv[gettop]+e->weight > etv[k]) {
etv[k] = etv[gettop] + e->weight;
}
}
}
printf("\n");
for (int i = 0; i<GL->numVertexes; i++) {
printf("etv[%d] = %d\n",i,etv[i]);
}
printf("\n");
if (count<GL->numVertexes) {
return ERROR;
}else{
return OK;
}
}
//求关键路径,GL为有向网,则输出G的各项关键活动
void CriticalPath(GraphAdjList GL){
//1.对GL进行拓扑排序,得到事件的最早发生时间etv,拓扑序列stack2
TopologicalSort(GL);
//2.定义事件的最晚发生时间,并初始化(etv的最后一个数据为最后一个事件发生的最早时间,以它来初始化ltv数组)
ltv = (int *)malloc(sizeof(int)*GL->numVertexes);
for (int i=0; i<GL->numVertexes; i++) {
//
ltv[i] = etv[GL->numVertexes -1];
}
int k;
int gettop;
EdgeNode *e;
//3.将事件栈stack2出栈
while (top2 != 0) {
//3.1将拓扑排序序列出栈,得到事件的下标
gettop = stack2[top2--];
//3.2找到与栈顶元素相连的点
for (e = GL->adjList[gettop].firstedge; e; e = e->next) {
k = e->adjvex;
//更新事件的最晚发生时间ltv
if (ltv[k]-e->weight < ltv[gettop]) {
ltv[gettop] = ltv[k] - e->weight;
}
}
}
//打印ltv数组
printf("ltv:\n");
for (int i=0; i<GL->numVertexes; i++) {
printf("ltv[%d] = %d\n",i,ltv[i]);
}
printf("\n");
int ete,lte;
//4.求ete,lte,如果ete和lte相等,则是关键活动
for (int j =0 ; j<GL->numVertexes; j++) {
for (e = GL->adjList[j].firstedge; e; e = e->next) {
k = e->adjvex;
//ete就是表示活动<Vk,Vj>的最早开工时间,是针对这条弧来说的,而这条弧的弧尾顶点Vk,的事件发生了,它才可以发生,因此ete = etv[k];
ete = etv[j];
//lte表示活动<Vk,Vj>的最晚开工时间,但此活动再晚也不能等Vj事件发生才开始,而是必须在Vj事件之前发生,lte = ltv[k] - len<Vk,Vj>
lte = ltv[k] - e->weight;
//如果ete == lte则,该活动为关键活动
if (ete == lte) {
printf("<%d,%d> weight:%d\n",GL->adjList[j].data,GL->adjList[k].data,e->weight);
}
}
}
}
int main(int argc, const char * argv[]) {
MGraph G;
GraphAdjList GL;
CreateMGraph(&G);
CreateALGraph(G, &GL);
//拓扑排序
// TopologicalSort(GL);
//关键路径
CriticalPath(GL);
return 0;
}