利用AOE网求解关键路径问题

1、关键路径问题的简要介绍

关键路径是从工程领域抽象出来的一类问题,这类问题的求解常用于工程完成所需时间的估算,包括完成整个工程至少需要多少时间?其中哪些子工程是影响工程进度的关键?

为求解此类问题,采用如下形式的图结构来表示工程:用弧(有向边)表示活动(子工程);用弧的权值表示活动的持续时间;用弧两端的顶点分别表示活动的开始和结束,叫做事件(即工程中的瞬间行)。这样的有向图称为AOE网(Activity On Edge)。显然,一个能正常进行的工程所对应的AOE网是一个有向无环图。由于整个工程通常有一个唯一的开始时间和结束时间,因此,相应地,在AOE网中分别对应一个顶点,称开始点(即入度为0的点)和结束点(即出度为0的点)。

由于有些活动只能依次进行,有些活动却可以并行进行,所以整个工程所需要的最少时间不是所有活动所需时间的累积,而是从开始点到结束点之间工期最长的一条路径,这条最长的路径即关键路径(Critical Path)。最长路径可能不止一条,在最长路径上的活动即关键活动(Critical Activity)。

2、程序框架设计

2.1、有向图的存储

构建一个graph类,使用邻接链表和逆邻接链表用来存储工程有向图。

graph类框架表

graph

public

function

graph(int x,int y)

构造函数

~graph()

析构函数

void creategraph(group test[])

存储有向图

void getindegrees(int ind[])

获取顶点入度

void getoutdegrees(int outd[])

获取顶点出度

void deletegraph()

删除有向图

data

int vernum

顶点数

int arcnum

弧数

group test[100]

group类型结构体

vnode verlist[100]

vnode类型结构体

graph类使用的结构体框架表

struct

group

存储每一条弧的起点、终点、事件、时间。

int start

起点

int end

终点

int thing

事件编号

int time

时间

enode

用于邻接链表,存储每一顶点邻接点、对应弧时间、邻接点指针

int adjver

邻接点编号

int data

时间

struct enode *enext

邻接点指针

cenode

用于逆邻接链表,存储每一顶点前邻接点、对应弧时间、前邻接点指针

int adjver

逆邻接点编号

int data

时间

struct cenode *cenext

逆邻接点指针

vnode

存储每一顶点的编号、对应邻接链表头指针、对应逆邻接链表头指针

int data

顶点编号

enode *ehead

邻接链表头指针

cenode *cehead

逆邻接链表头指针

2.2、数据结构链栈

构建一个lstack链栈类,用于主程序使用。

lstack类框架表

lstack

public

function

lstack()

构造函数

~lstack()

析构函数

void pushstack(int x)

入栈函数

int popstack()

出栈函数

data

snode *top

snode类型结构体指针

lstack类使用的结构体框架表

struct

snode

链栈数据、指针

int data

压栈数据

struct snode *next

链栈指针

2.3、主程序框架

主程序用来求出AOE网中的所有关键活动,由以下几个子程序组成。

邻接链表拓扑排序topo:使用邻接链表来判断AOE网是否有环,以判断是否能够继续求出关键活动,同时求出每个顶点的最早发生时间。

‚逆邻接链表拓扑排序ctopo:使用逆邻接链表求出每个顶点的最迟发生时间。

ƒ关键活动aoe:通过判断每一个顶点的最早发生时间是否等于最迟发生时间求出关键路径上的顶点即事件以及关键活动。

主程序框架表

main program

function

bool topo(int x,lstack s,int ind[],int e[],graph g)

邻接链表拓扑排序

void ctopo(int x,lstack s,int outd[],int e[],int l[],graph g)

逆邻接链表拓扑排序

void aoe(int x,int y,int cv[],int ca[],lstack s,int outd[],int e[],int l[],graph g)

求关键活动子程序

int main()

主函数,见流程图

data

int count

全局变量,统计关键活动个数

int x

有向图顶点数

int y

有向图弧数

int ind[100]

顶点入度数组

int outd[100]

顶点出度数组

int e[100]

顶点最早发生时间数组

int l[100]

顶点最迟发生时间数组

int cv[100]

关键路径上的事件

int ca[100]

关键路径上的活动

lstack s

lstack类型变量s

graph g(x,y)

graph类型变量g

程序具体运行过程中有教导用户如何使用的交互语句,但是为了用户更好的使用,还是特地将步骤以及注意事项介绍如下:

1、用户需要在运行程序之前在该程序所在文件夹目录下,创建一个txt文档,并按照xxx.txt的格式命名该文档。用户需要在该文档中输入所要求解的AOE网的数据,输入的要求见下方“输入数据格式”。

之所以选择将数据输入txt文档,是居于以下几个原因:

考虑到用户所要求的AOE网数据较多,相比于在程序运行过程中输入数据,将数据输入txt文档再由程序读取更为方便。

‚在程序运行过程中输入数据,极有可能由于疏忽输入了错误的数据,于是只能关闭程序,从头再来,浪费时间浪费精力。

ƒ程序运行的结果,在运行界面显示的同时,也会输入到同一txt文档中,便于用户后期查看运行结果。

输入数据格式:

start       end         activity        time

   活动起点  活动终点  AOE网中的某一活动  活动时间

附注:每一活动占一行,每个数据之间用空格隔开。

         ‚所有数据均为数字,即活动、事件的标号均为数字。

         ƒ从开始点标号为1开始,按从左到右从上到下的顺序给每个顶点标 号,一直到结束点。

2、运行程序。按照程序运行界面的汉字提示,一步一步运行程序。当程序运行结束了,用户可以查看txt文档来查看运行结果。

3、程序运行的结果,是给出所有的关键活动以及对应数据。

输出数据格式:

activity   start    end     s_earliest_time   e_latest_time

关键活动 活动起点 活动终点 起点最早发生时间 终点最迟发生时间

附注:每一活动占一行,每个数据之间用空格隔开。

  ‚由于关键活动的最早、最迟发生时间相同,故而选择输出关键活动起点最早发生时间,终点最迟发生时间,以用来互相比较。

//AOE
#include<cstdio>
using namespace std;
//define linkedstack
struct snode
{
	int data;
	struct snode *next;
};
class lstack
{
	public:
		lstack();
		~lstack();
		void pushstack(int x);
		int popstack();
		snode *top;	
};
lstack::lstack()
{
	top=NULL;
}
lstack::~lstack()
{
	
}
void lstack::pushstack(int x)
{
	snode *s;
	s=new snode;
	s->data=x;
	s->next=top;
	top=s;
}
int lstack::popstack()
{
	snode *u;
	int x;
	if(top==NULL)
		return 0;
	else
	{
		x=top->data;
		u=top;
		top=top->next;
		delete u;
		return x;
	} 
}
//define graph
struct group
{
	int start;
	int end;
	int thing;
	int time;
};
struct enode
{
	int adjver;
	int data;
	struct enode *enext;
};
struct cenode
{
	int adjver;
	int data;
	struct cenode *cenext;
};
struct vnode
{
	int data;
	enode *ehead;
	cenode *cehead;
};
class graph
{
	public:
		graph(int x,int y);
		~graph();
		void creategraph(group test[]);
		void getindegrees(int ind[]);
		void getoutdegrees(int outd[]);
		void deletegraph();
		int vernum;
		int arcnum;
		group test[100];
		vnode verlist[100];
};
graph::graph(int x,int y)
{
	vernum=x;
	arcnum=y;
	for(int i=1;i<=vernum;i++)
	{
		verlist[i].data=i;
		verlist[i].ehead=new enode;
		verlist[i].ehead->enext=NULL;
		verlist[i].cehead=new cenode;
		verlist[i].cehead->cenext=NULL;
	}
}
graph::~graph()
{

}
void graph::creategraph(group test[])
{ 
	for(int j=1;j<=vernum;j++)
	{
		for(int i=1;i<=arcnum;i++)
		{
			if(test[i].start==verlist[j].data)
			{
				enode *etemp;
				etemp=new enode;
				etemp->adjver=test[i].end;
				etemp->data=test[i].time;
				etemp->enext=verlist[j].ehead->enext;
				verlist[j].ehead->enext=etemp;
			}
		}
		for(int i=1;i<=arcnum;i++)
		{
			if(test[i].end==verlist[j].data)
			{
				cenode *cetemp;
				cetemp=new cenode;
				cetemp->adjver=test[i].start;
				cetemp->data=test[i].time;
				cetemp->cenext=verlist[j].cehead->cenext;
				verlist[j].cehead->cenext=cetemp;
			}
		}
	}
}
void graph::getindegrees(int ind[])
{
	cenode *cep;
	for(int i=1;i<=vernum;i++)
	{
		ind[i]=0;
		cep=verlist[i].cehead->cenext;
		while(cep!=NULL)
		{
			ind[i]++;
			cep=cep->cenext;
		}
	}
}
void graph::getoutdegrees(int outd[])
{
	enode *ep;
	for(int i=1;i<=vernum;i++)
	{
		outd[i]=0;
		ep=verlist[i].ehead->enext;
		while(ep!=NULL)
		{
			outd[i]++;
			ep=ep->enext;
		}
	}
}
void graph::deletegraph()
{
	for(int i=1;i<=vernum;i++)
	{
		while(verlist[i].ehead->enext!=NULL)
		{
			enode *eu;
			eu=verlist[i].ehead->enext;
			verlist[i].ehead->enext=eu->enext;
			delete eu;
		}
		delete verlist[i].ehead;
		while(verlist[i].cehead->cenext!=NULL)
		{
			cenode *ceu;
			ceu=verlist[i].cehead->cenext;
			verlist[i].cehead->cenext=ceu->cenext;
			delete ceu;
		}
		delete verlist[i].cehead;
	}
}
//main program
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
int count;
bool topo(int x,lstack s,int ind[],int e[],graph g);
void ctopo(int x,lstack s,int outd[],int e[],int l[],graph g);
void aoe(int x,int y,int cv[],int ca[],lstack s,int outd[],int e[],int l[],graph g);
int main()
{
	cout<<"please build a file named as xxx.txt in the program folder"<<endl;
	cout<<"please input data in rules"<<endl;
	cout<<"are you ready?if so,click enter"<<endl;
	system("pause");
	int x,y,ind[100],outd[100],e[100],l[100],cv[100],ca[100];
	lstack s;
	cout<<"please input how many events and activities are"<<endl;
	cin>>x>>y;
	graph g(x,y);
	string filename;
	cout<<"please input the filename you just built"<<endl;
	cin>>filename;
	ifstream infile;
	infile.open(filename.c_str());
	if(!infile.is_open())
	{
		cerr<<"cannot read file,please restart"<<endl;
		return 0;
	}
	else
	{
		for(int i=1;i<=y;i++)
			infile>>g.test[i].start>>g.test[i].end>>g.test[i].thing>>g.test[i].time;
	}
	infile.close();
	cout<<"succeed to read file,please click enter"<<endl;
	system("pause");
	ofstream outfile;
	outfile.open(filename.c_str(),ios::app);
	outfile<<endl;
	g.creategraph(g.test);
	g.getindegrees(ind);
	g.getoutdegrees(outd);
	if(topo(x,s,ind,e,g))
	{
		cout<<"topologicalsort succeed"<<endl;
		outfile<<"topologicalsort succeed"<<endl;
		cout<<"the needed time of AOE is "<<e[x]<<endl;
		outfile<<"the needed time of AOE is "<<e[x]<<endl;
		ctopo(x,s,outd,e,l,g);
		aoe(x,y,cv,ca,s,outd,e,l,g);
		cout<<"there are "<<count<<" critical activities"<<endl;
		outfile<<"there are "<<count<<" critical activities"<<endl;
		cout<<"activity"<<"    "<<"start"<<"    "<<"end"<<"    "<<"s_earliest_time"<<"    "<<"e_latest_time"<<endl;
		outfile<<"activity"<<"    "<<"start"<<"    "<<"end"<<"    "<<"earliest_time"<<"    "<<"latest_time"<<endl;
		for(int i=count;i>=1;i--)
		{
			cout<<g.test[ca[i]].thing<<"            "<<g.test[ca[i]].start<<"        "<<g.test[ca[i]].end<<"            "<<e[g.test[ca[i]].start]<<"            "<<l[g.test[ca[i]].end]<<endl;
			outfile<<g.test[ca[i]].thing<<"            "<<g.test[ca[i]].start<<"        "<<g.test[ca[i]].end<<"            "<<e[g.test[ca[i]].start]<<"            "<<l[g.test[ca[i]].end]<<endl;
		}
		outfile.close();
		g.deletegraph();
		return 0;
	}
	else
	{
		cout<<"topologicalsort fail"<<endl;
		outfile<<"topologicalsort fail"<<endl;
		outfile.close();
		g.deletegraph();
		return 0;
	}
}
bool topo(int x,lstack s,int ind[],int e[],graph g)
{
	for(int i=1;i<=x;i++)
		e[i]=0;
	int v1,v2,vcount=0;
	for(int i=1;i<=x;i++)
	{
		if(ind[i]==0)
			s.pushstack(i);	
	}
	while(s.top!=NULL)
	{
		v1=s.popstack();
		vcount++;
		enode *eq;
		eq=g.verlist[v1].ehead->enext;
		while(eq!=NULL)
		{
			v2=eq->adjver;
			ind[v2]--;
			if(e[v1]+eq->data>e[v2])
				e[v2]=e[v1]+eq->data;
			if(ind[v2]==0)
				s.pushstack(v2);
			eq=eq->enext;
		}
	}
	if(vcount==x)
		return true;
	else
		return false;
}
void ctopo(int x,lstack s,int outd[],int e[],int l[],graph g)
{
	for(int i=x;i>=1;i--)
		l[i]=e[x];
	int v1,v2;
	for(int i=x;i>=1;i--)
	{
		if(outd[i]==0)
			s.pushstack(i);
	}
	while(s.top!=NULL)
	{
		v1=s.popstack();
		cenode *ceq;
		ceq=g.verlist[v1].cehead->cenext;
		while(ceq!=NULL)
		{
			v2=ceq->adjver;
			outd[v2]--;
			if(l[v1]-ceq->data<l[v2])
				l[v2]=l[v1]-ceq->data;
			if(outd[v2]==0)
				s.pushstack(v2);
			ceq=ceq->cenext;
		}
	}
}
void aoe(int x,int y,int cv[],int ca[],lstack s,int outd[],int e[],int l[],graph g)
{
	int num=0;
	for(int i=x;i>=1;i--)
	{
		if(e[i]==l[i])
		{
			num++;
			s.pushstack(i);
		}	
	}
	count=num;
	for(int j=1;j<=num;j++)
		cv[j]=s.popstack();
	for(int i=1;i<=num;i++)
	{
		for(int j=1;j<=y;j++)
		{
			if(g.test[j].start==cv[i])
			{
				for(int k=1;k<=num;k++)
				{
					if(g.test[j].end==cv[k])
						s.pushstack(j);
				}
			}
		}
	}
	for(int i=1;i<=num;i++)
		ca[i]=s.popstack();	
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值