有向无环图(AOE)的拓扑排序和关键路径

问题:有向无环图的拓扑排序

拓扑排序:由某个集合上的一个偏序关系得到该集合上的一个全序关系。

算法用了一个全局数组InDegreee来记录集合中顶点的入度,用栈来保存入度为0的元素。首先让所有入度为0的顶点进栈,然后让栈中的元素出栈,出栈过程中,与该顶点相连的顶点的入度相应减1,若入度变为0了,则相应入栈。

结束状态:所有元素的入度都为0,栈为空,所有顶点元素都已经完成拓扑排序;否则,存在环路。

#include<iostream>
using namespace std;
#define MAX 100           //顶点的最大个数
int InDegree[MAX+1];      //记录顶点入度的数组
typedef char SElemType;   //定义栈的数据类型
typedef int Status;       //定义栈操作的返回值类型
#define ERROR 0           //栈操作失败的返回值
#define OK    1           //栈操作成功的返回值
#define MAXNAME 5         //活动名字的最长值
#define INFINIT INT_MAX   //定义最大整数
typedef struct stack
{
	SElemType *base;
	SElemType *top;
	int stacksize;
}stack;                 //栈定义
Status Init(stack &s)     //栈的初始化
{
	s.base=new char[MAX];
	if(s.base==NULL)
	{
		cout<<"栈内存空间申请不成功~"<<endl;
		return ERROR;
	}
	s.top=s.base;
	s.stacksize=0;
	return OK;
}
Status Push(stack &s,char ch)
{
	if(s.stacksize==MAX)
	{
		cout<<"栈内存向上溢出~"<<endl;
		return ERROR;
	}
	*s.top++=ch;
	s.stacksize++;
	return OK;
}
Status Pop(stack &s,char &ch)
{
	if(0==s.stacksize)
	{
		cout<<"栈内存向下溢出~"<<endl;
		return ERROR;
	}
	s.top--;
	ch=*(s.top);
	s.stacksize--;
	return OK;
}
int Empty(stack s)
{
	if(s.base==s.top)
		return 1;
	else
		return 0;
}
typedef struct ArcNode
{
	int adjvex;
	int weight;
	int a;              //该弧对应的活动的序号
	struct ArcNode* nextarc;
}ArcNode;    //表结点的定义
typedef struct HNode
{
	char info;
	ArcNode *firstarc;
}HNode,AdjList[MAX+1];  //头结点和顶点数组的定义,其中,顶点数组的0号单元不存储
typedef struct ALGraph
{
	AdjList	vertex;
	int vexnum;
	int arcnum;
}ALGraph;           //邻接表的定义
int LocateVex(ALGraph G,char ch)   //定位顶点在邻接表中的位置
{
	for(int i=1;i<=G.vexnum;i++)
	{
		if(ch==G.vertex[i].info)
			return i;
	}
	return 0;
}
void CreateALGraph(ALGraph &G)      //创建邻接表
{
	char ch1,ch2;
	int w;
	int pos1,pos2;
	int s;
	ArcNode *p,*q;
	cout<<"请输入顶点个数和边数:";
	cin>>G.vexnum>>G.arcnum;
	cout<<"请依次输入"<<G.vexnum<<"个顶点的信息:";
	for(int i=1;i<=G.vexnum;i++)
	{
		cin>>G.vertex[i].info;
		G.vertex[i].firstarc=NULL;
	}
	cout<<"请依次输入每条弧的弧尾 弧头 权值以及该弧对应的活动序号:"<<endl;
	cout<<'H'<<' '<<'T'<<' '<<'W'<<' '<<'N'<<endl;
	for(i=1;i<=G.arcnum;i++)
	{	
		cin>>ch1>>ch2>>w>>s;
		pos1=LocateVex(G,ch1);
		pos2=LocateVex(G,ch2);
		q=new ArcNode;
		q->adjvex=pos2;
		q->nextarc=NULL;
		q->weight=w;
		q->a=s;
		p=G.vertex[pos1].firstarc;
		if(p==NULL)
			G.vertex[pos1].firstarc=q;
		else
		{
			while(p->nextarc!=NULL)
			{
				p=p->nextarc;
			}
			p->nextarc=q;
		}
		InDegree[pos2]++;
	}
}
Status PoloSort(ALGraph G,int ee[],int el[])
{
	stack s,t;
	Init(s);
	Init(t);
	char ch;
	int pos1,pos2;
	int num=0;
	ArcNode *p;
	for(int i=1;i<G.vexnum;i++)
	{
		ee[i]=0;
	}
	for(i=1;i<G.vexnum;i++)
	{
		el[i]=INFINIT;
	}
	for(i=1;i<=G.vexnum;i++)
	{
		if(0==InDegree[i])
		{
			Push(s,G.vertex[i].info);
		}
	}
	cout<<"拓扑排序为:";
	while(!Empty(s))
	{
		Pop(s,ch);
		cout<<ch<<' ';
		Push(t,ch);
		num++;
		pos1=LocateVex(G,ch);
		p=G.vertex[pos1].firstarc;
		while(p!=NULL)
		{
			pos2=p->adjvex;
			if(ee[pos1]+p->weight>ee[pos2])
				ee[pos2]=ee[pos1]+p->weight;			
			InDegree[pos2]--;
			if(0==InDegree[pos2])
				Push(s,G.vertex[pos2].info);
			p=p->nextarc;
		}
	}
	cout<<endl;
	if(num==G.vexnum)
	{
		cout<<"顶点序列中所有元素都已经完成排序,拓扑排序成功~"<<endl;
	}
	else
	{
		cout<<"顶点序列中存在环路,不能实现拓扑排序~"<<endl;
		return ERROR;
	}
	Pop(t,ch);
	pos1=LocateVex(G,ch);
	el[pos1]=ee[pos1];   //最后一个事件的最早发生时间和最迟发生时间相同
	while(!Empty(t))
	{
		Pop(t,ch);
		pos1=LocateVex(G,ch);
		p=G.vertex[pos1].firstarc;
		while(p!=NULL)
		{
			pos2=p->adjvex;
			if(el[pos2]-p->weight<el[pos1])
				el[pos1]=el[pos2]-p->weight;
			p=p->nextarc;
		}
	}
	return OK;
}
void CriticalPath(ALGraph G,int ee[],int el[])
{
	int i;
	int *e=new int[G.arcnum+1];       //活动的最早发生时间
	int *l=new int[G.arcnum+1];       //活动的最迟发生时间
	ArcNode *p;
	int pos1,pos2;
	int pos;
	char *n=new char[MAXNAME];
	for(i=1;i<=G.vexnum;i++)
	{
		pos1=i;
		p=G.vertex[i].firstarc;
		while(p!=NULL)
		{
			pos2=p->adjvex;
			pos=p->a;
			e[pos]=ee[pos1];
			l[pos]=el[pos2]-p->weight;
			p=p->nextarc;
		}
	}
	for(i=1;i<=G.arcnum;i++)
	{
		if(e[i]==l[i])
			cout<<"活动"<<i<<"为关键活动"<<endl;
	}
}

void main()
{
	ALGraph G;
	CreateALGraph(G);
	int *ee=new int[G.vexnum+1];       //数组ee记录事件的最早发生时间
	int *el=new int[G.vexnum+1];       //数组el记录事件的最迟发生时间
	PoloSort(G,ee,el);
	CriticalPath(G,ee,el);
}
------------------------------------------------------------------------------
运行结果:
请输入顶点个数和边数:9 11
请依次输入9个顶点的信息:a b c d e f g h i
请依次输入每条弧的弧尾 弧头 权值以及该弧对应的活动序号:
H T W N
a b 6 1
a c 4 2
a d 5 3
b e 1 4
c e 1 5
d f 2 6
e g 9 7
e h 7 8
f h 4 9
g i 2 10
h i 4 11
拓扑排序为:a d f c b e h g i
顶点序列中所有元素都已经完成排序,拓扑排序成功~
活动1为关键活动
活动4为关键活动
活动7为关键活动
活动8为关键活动
活动10为关键活动
活动11为关键活动
Press any key to continue
------------------------------------------------------------------------------


To_make_progress,everyday!


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值