1. 程式人生 > >_DataStructure_C_Impl:AOE網的關鍵路徑

_DataStructure_C_Impl:AOE網的關鍵路徑

adjlist 存儲 pos 輸出 回路 無向圖 structure amp cal

//_DataStructure_C_Impl:CriticalPath
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"SeqStack.h"
//圖的鄰接表類型定義
typedef char VertexType[4];
typedef int InfoPtr;	//定義為整型,為了存放權值
typedef int VRType;

#define MaxSize 50	 //最大頂點個數
typedef enum{DG,DN,UG,UN}GraphKind;		//圖的類型:有向圖、有向網、無向圖和無向網
//邊結點的類型定義
typedef struct ArcNode{
	int adjvex;	//鄰接點域,弧指向的頂點的位置
	InfoPtr *info;	//弧的權值
	struct ArcNode *nextarc;	//指示下一個與該頂點相鄰接的頂點
}ArcNode;
//頭結點的類型定義
typedef struct VNode{
	VertexType data;	//用於存儲頂點
	ArcNode *firstarc;	//指示第一個與該頂點鄰接的頂點
}VNode,AdjList[MaxSize];
//圖的類型定義
typedef struct{
	AdjList vertex;
	int vexnum,arcnum;	//圖的頂點數目與弧的數目
	GraphKind kind;	//圖的類型
}AdjGraph;
//返回圖中頂點相應的位置
int LocateVertex(AdjGraph G,VertexType v){
	int i;
	for(i=0;i<G.vexnum;i++)
		if(strcmp(G.vertex[i].data,v)==0)
			return i;
	return -1;
}
//採用鄰接表存儲結構,創建有向網N
void CreateGraph(AdjGraph *N){
	int i,j,k,w;
	VertexType v1,v2;	//定義兩個頂點v1和v2
	ArcNode *p;
	printf("請輸入圖的頂點數,邊數(逗號分隔): ");
	scanf("%d,%d",&(*N).vexnum,&(*N).arcnum);
	printf("請輸入%d個頂點的值:\n",N->vexnum);
	for(i=0;i<N->vexnum;i++){
		scanf("%s",N->vertex[i].data);
		N->vertex[i].firstarc=NULL;	//將相關聯的頂點置為空
	}
	printf("請輸入弧尾和弧頭(以空格作為間隔):\n");
	for(k=0;k<N->arcnum;k++){	//建立邊鏈表
		scanf("%s%s%*c%d",v1,v2,&w);
		i=LocateVertex(*N,v1);
		j=LocateVertex(*N,v2);
		//j為弧頭i為弧尾創建鄰接表
		p=(ArcNode *)malloc(sizeof(ArcNode));
		p->adjvex=j;
		p->info=(InfoPtr*)malloc(sizeof(InfoPtr));
		*(p->info)=w;
		//將p指向的結點插入到邊表中
		p->nextarc=N->vertex[i].firstarc;
		N->vertex[i].firstarc=p;
	}
	(*N).kind=DN;
}
//銷毀無向圖G
void DestroyGraph(AdjGraph *G){
	int i;
	ArcNode *p,*q;
	for(i=0;i<(*G).vexnum;++i){	//釋放圖中的邊表結點
		p=G->vertex[i].firstarc;	//p指向邊表的第一個結點
		if(p!=NULL){	//假設邊表不為空,則釋放邊表的結點
			q=p->nextarc;
			free(p);
			p=q;
		}
	}
	(*G).vexnum=0;	//將頂點數置為0
	(*G).arcnum=0;	//將邊的數目置為0
}
//輸出圖的鄰接表
void DisplayGraph(AdjGraph G){
	int i;
	ArcNode *p;
	printf("%d個頂點:\n",G.vexnum);
	for(i=0;i<G.vexnum;i++)
		printf("%s ",G.vertex[i].data);
	printf("\n%d條邊:\n",G.arcnum);
	for(i=0;i<G.vexnum;i++)
	{
		p=G.vertex[i].firstarc;
		while(p)
		{
			printf("<%s,%s,%d> ",G.vertex[i].data,G.vertex[p->adjvex].data,*(p->info));
			p=p->nextarc;
		}
		printf("\n");
	}
}
//*********************************************************
int ve[MaxSize]; //ve存放事件最早發生時間
/*採用鄰接表存儲結構的有向網N的拓撲排序,並求各頂點相應事件的最早發生時間ve*/
/*假設N無回路。則用用棧T返回N的一個拓撲序列,並返回1,否則為0*/
int TopologicalOrder(AdjGraph N,SeqStack *T){
	int i,k,count=0;
	int indegree[MaxSize];	//數組indegree存儲各頂點的入度
	SeqStack S;
	ArcNode *p;
	//將圖中各頂點的入度保存在數組indegree中
	for(i=0;i<N.vexnum;i++) //將數組indegree賦初值
		indegree[i]=0;
	for(i=0;i<N.vexnum;i++){
		p=N.vertex[i].firstarc;
		while(p!=NULL){
			k=p->adjvex;
			indegree[k]++;
			p=p->nextarc;
		}
	}
	//初始化棧S
	InitStack(&S);
	printf("拓撲序列:");
	for(i=0;i<N.vexnum;i++)
		if(!indegree[i])	//將入度為零的頂點入棧
			PushStack(&S,i);
	InitStack(T);	//初始化逆拓撲排序頂點棧
	for(i=0;i<N.vexnum;i++)	//初始化ve
		ve[i]=0;
	while(!StackEmpty(S)){	//假設棧S不為空
		PopStack(&S,&i);	//從棧S將已拓撲排序的頂點i彈出
		printf("%s ",N.vertex[i].data);
		PushStack(T,i);	//i號頂點入逆拓撲排序棧T
		count++;	//對入棧T的頂點計數
		for(p=N.vertex[i].firstarc;p;p=p->nextarc){	//處理編號為i的頂點的每一個鄰接點
			k=p->adjvex;		//頂點序號為k
			if(--indegree[k]==0)	//假設k的入度減1後變為0,則將k入棧S
				PushStack(&S,k);
			if(ve[i]+*(p->info)>ve[k])	//計算頂點k相應的事件的最早發生時間
				ve[k]=ve[i]+*(p->info);
		}
	}
	if(count<N.vexnum){
		printf("該有向網有回路\n");
		return 0;
	}else
		return 1;
}
//輸出AOE網N的關鍵路徑
int CriticalPath(AdjGraph N){
	int vl[MaxSize];	//事件最晚發生時間
	SeqStack T;
	int i,j,k,e,l,dut,value,count,e1[MaxSize],e2[MaxSize];
	ArcNode *p;
	if(!TopologicalOrder(N,&T))	//假設有環存在,則返回0
		return 0;
	value=ve[0];
	for(i=1;i<N.vexnum;i++)
		if(ve[i]>value)
			value=ve[i];	//value為事件的最早發生時間的最大值
	for(i=0;i<N.vexnum;i++) //將頂點事件的最晚發生時間初始化
		vl[i]=value;
	while(!StackEmpty(T))	//按逆拓撲排序求各頂點的vl值
		for(PopStack(&T,&j),p=N.vertex[j].firstarc;p;p=p->nextarc){ //彈出棧T的元素,賦給j,p指向j的後繼事件k
			k=p->adjvex;
			dut=*(p->info);	//dut為弧<j,k>的權值
			if(vl[k]-dut<vl[j])//計算事件j的最遲發生時間
				vl[j]=vl[k]-dut;
		}
		printf("\n事件的最早發生時間和最晚發生時間\ni ve[i] vl[i]\n");
		for(i=0;i<N.vexnum;i++)		//輸出頂點相應的事件的最早發生時間最晚發生時間
			printf("%d   %d     %d\n",i,ve[i],vl[i]);
		printf("關鍵路徑為:(");
		for(i=0;i<N.vexnum;i++) //輸出關鍵路徑經過的頂點
			if(ve[i]==vl[i])
				printf("%s ",N.vertex[i].data);
		printf(")\n");
		count=0;
		printf("活動最早開始時間和最晚開始時間\n   弧    e   l   l-e\n");
		for(j=0;j<N.vexnum;j++)
			for(p=N.vertex[j].firstarc;p;p=p->nextarc){
				k=p->adjvex;
				dut=*(p->info);	//dut為弧<j,k>的權值
				e=ve[j];		//e就是活動<j,k>的最早開始時間
				l=vl[k]-dut;	//l就是活動<j,k>的最晚開始時間
				printf("%s→%s %3d %3d %3d\n",N.vertex[j].data,N.vertex[k].data,e,l,l-e);
				if(e==l){	//將關鍵活動保存在數組中
					e1[count]=j;
					e2[count]=k;
					count++;
				}
			}
		printf("關鍵活動為:");
		for(k=0;k<count;k++)		//輸出關鍵路徑
		{
			i=e1[k];
			j=e2[k];
			printf("(%s→%s) ",N.vertex[i].data,N.vertex[j].data);
		}
		printf("\n");
	return 1;
}
void main(){
	AdjGraph N;
	CreateGraph(&N);		/*採用鄰接表存儲結構創建有向網N*/
	DisplayGraph(N);		/*輸出有向網N*/
	CriticalPath(N);		/*求網N的關鍵路徑*/
	DestroyGraph(&N);		/*銷毀網N*/
	system("pause");
}

#pragma once
#include<stdio.h>
#include<stdlib.h>
#define StackSize 100
typedef int DataType;	//棧元素類型定義
typedef struct{
	DataType stack[StackSize];
	int top;
}SeqStack;
//將棧初始化為空棧僅僅須要把棧頂指針top置為
void InitStack(SeqStack *S){
	S->top=0;//把棧頂指針置為0
}
//推斷棧是否為空。棧為空返回1,否則返回0
int StackEmpty(SeqStack S){
	if(S.top==0)
		return 1;
	else
		return 0;
}
//取棧頂元素。將棧頂元素值返回給e,並返回1表示成功;否則返回0表示失敗。
int GetTop(SeqStack S,DataType *e){
	if(S.top<=0){		//在取棧頂元素之前。推斷棧是否為空
		printf("棧已經空!\n");
		return 0;
	}else{
		*e=S.stack[S.top-1];	//在取棧頂元素
		return 1;
	}
}
//將元素e進棧。元素進棧成功返回1,否則返回0
int PushStack(SeqStack *S,DataType e){
	if(S->top>=StackSize){	//在元素進棧前,推斷是否棧已經滿
		printf("棧已滿。不能進棧!

\n"); return 0; }else{ S->stack[S->top]=e; //元素e進棧 S->top++; //改動棧頂指針 return 1; } } //出棧操作。將棧頂元素出棧。並將其賦值給e。出棧成功返回1。否則返回0 int PopStack(SeqStack *S,DataType *e){ if(S->top<=0){ //元素出棧之前,推斷棧是否為空 printf("棧已經沒有元素,不能出棧!\n"); return 0; }else{ S->top--; //先改動棧頂指針。即出棧 *e=S->stack[S->top]; //將出棧元素賦值給e return 1; } } //求棧的長度。即棧中元素個數,棧頂指針的值就等於棧中元素的個數 int StackLength(SeqStack S){ return S.top; } //清空棧的操作 void ClearStack(SeqStack *S){ S->top=0; }

技術分享

_DataStructure_C_Impl:AOE網的關鍵路徑