• _DataStructure_C_Impl:AOE网的关键路径


    //_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->vexnum);
    	for(i=0;i<N->vexnum;i++){
    		scanf("%s",N->vertex[i].data);
    		N->vertex[i].firstarc=NULL;	//将相关联的顶点置为空
    	}
    	printf("请输入弧尾和弧头(以空格作为间隔):
    ");
    	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个顶点:
    ",G.vexnum);
    	for(i=0;i<G.vexnum;i++)
    		printf("%s ",G.vertex[i].data);
    	printf("
    %d条边:
    ",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("
    ");
    	}
    }
    //*********************************************************
    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("该有向网有回路
    ");
    		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("
    事件的最早发生时间和最晚发生时间
    i ve[i] vl[i]
    ");
    		for(i=0;i<N.vexnum;i++)		//输出顶点相应的事件的最早发生时间最晚发生时间
    			printf("%d   %d     %d
    ",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(")
    ");
    		count=0;
    		printf("活动最早開始时间和最晚開始时间
       弧    e   l   l-e
    ");
    		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.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("
    ");
    	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("栈已经空!
    ");
    		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("栈已满。不能进栈!

    "); 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("栈已经没有元素,不能出栈! "); 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; }


  • 相关阅读:
    servlet中getWriter和getOutputStream的区别
    一个页面访问错误的问题
    sendRedirect实现原理分析
    servlet开发细节
    tomcat 目录分析
    servlet杂谈
    SQL 查询中的like子句的另一种实现方法,速度比like快
    让复合控件的子控件获得设计时支持
    bug管理工具——Gemini
    HtmlAgilityPack获取#开头节点的XPath
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7077884.html
Copyright © 2020-2023  润新知