图论-AOV网与拓扑排序&AOE网与关键路径 c++

AOV网为有向图,用其表示一项工程,则顶点表示活动,弧表示活动之间的优先关系。此时AOV网中不能出现回路,否则会出现某活动开始是以自身为先决条件这样的问题。拓扑排序就是用以测试AOV网是否存在回路的方法。拓扑排序适合图的邻接表存储形式。

拓扑序列:对有向图G=(V,E),V中顶点序列v0,v1,…,vn-1为拓扑序列,当且仅当满足:若从顶点vi到vj存在一条路径,则在顶点序列中vi一定在vj之前。

/*边表结点*/
struct ArcNode
{
	int adjvex;
	ArcNode* next;
};

/*顶点表结点
按需要在顶点表加入某顶点的入度*/
template<class DataType>
struct VertexNode
{
	DataType vertex;
	int in;
	ArcNode* first;
};

/*邻接表*/
template <class DataType>
class ALGraph
{
	friend void TopSort(ALGraph<DataType>&);

public:
	ALGraph(std::vector<DataType>& a, int n)
	{
		vertex_num = n;
		for (int i = 0; i < vertex_num; ++i)
		{
			VertexNode<DataType> temp;
			temp.vertex = a[i];
			temp.first = NULL;
			temp.in = 0;
			adjlist.push_back(temp);
		}

		int i, j;
		int l;
		while (cin >> i >> j >> l)
		{
			if (i == -1)
				break;
			ArcNode *s;
			s = new ArcNode;
			s->adjvex = j;
			s->next = adjlist[i].first;
			adjlist[i].first = s;
			++adjlist[j].in;
		}

	}

	~ALGraph()
	{
		for (int i=0; i < vertex_num; ++i)
		{
			ArcNode* q;
			while (adjlist[i].first != NULL)
			{
				q = adjlist[i].first;
				adjlist[i].first = adjlist[i].first->next;
				delete q;
			}
		}
	}

private:
	std::vector<VertexNode<DataType>> adjlist;//顶点表
	size_t vertex_num;

};

/*拓扑排序
1.将所有入度为0的点入栈
2.栈顶元素i出栈,输出i
3.对i的每一个邻接点k的入度-1;若k的入度为0,入栈
4.重复2,3直到所有点被遍历*/
void TopSort(ALGraph<int>& G)
{
	list<int> S;//栈S
	int count = 0;
	for (size_t i = 0; i < G.vertex_num; ++i)
		if (G.adjlist[i].in == 0)
			S.push_front(i);
	while (S.begin()!=S.end())
	{
		int i = *(S.begin());
		S.pop_front();
		cout << G.adjlist[i].vertex << endl;
		++count;
		ArcNode* p = G.adjlist[i].first;
		while (p != NULL)
		{
			int j = p->adjvex;
			--G.adjlist[j].in;
			if (G.adjlist[j].in == 0)
				S.push_front(j);
			p = p->next;
		}
	}
	if (count < G.vertex_num)
		cout << "有回路" << endl;

}

与AOV网不同,AOE网的顶点表示事件,有向边表示活动,其权值表示活动持续时间,没有入边的为起点,没有出边的为终点。与AOV网相同的是其有向边代表了事件的优先顺序以及事件与活动的关系。因为某些活动能同时进行,从起点到终点有许多条路径,AOE网的关键路径是其中一条最大路径长度的路径,其路径长度即为工程所用最短工期,路径上的活动为关键活动,关键路径的算法就是求解AOE网中的关键活动。关键路径不能出现回路,即需要满足拓扑排序及逆拓扑排序,同时,关键路径也不唯一,若一个关键活动不在所有关键路径上,改变它将不影响工期。
要求解关键活动,需要求出4个值(1)事件最早发生时间ve[k](2)事件最晚发生时间vl[k](3)活动最早开始时间ee[i](4)活动最晚开始时间el[i];对于一个活动,若它是关键活动,则此活动的最早最晚开始时间应相等ee[i]=el[i],即想改变工期须改变关键活动。 对于活动i <vj,vk>
(1) 源点到vk的最大路径长度。ve[0]=0; ve[k]=max{ve[j]+length<vj,vk>};
(2) vl[n-1]=ve[n-1]; vl[j]=min{vl[k]-length<vj,vk>};
(3) ee[i]=ve[k];
(4) el[i]=vl[k]-length<vj,vk>
步骤:
1. 从源点v0出发按拓扑排序求其余各顶点的ve[],若存在回路,终止
2.从终点vn-1出发按逆拓扑排序求其余各顶点vl[],若存在回路,终止
3.根据各顶点的ve和vl,求各点的ee和el
4.若某条有向边ai满足ee[]=el[],则ai为关键路径

/*边表结点*/
struct ArcNode
{
	int ee, el;
	int len;
	int adjvex;
	bool flag;//是否在关键路径上

};

/*顶点表结点*/
template<class DataType>
struct VertexNode
{
	DataType vertex;
	int ve, vl;
	int in,out;
	bool is_end;
	list<ArcNode> vin, vout;
};

/*邻接表求关键路径*/
template <class DataType>
class ALGraph
{
public:
	ALGraph(std::vector<DataType>& a, int n)
	{
		vertex_num = n;
		for (int i = 0; i < vertex_num; ++i)
		{
			VertexNode<DataType> temp;
			temp.vertex = a[i];
			temp.in = 0;
			temp.out = 0;
			temp.ve = 0;
			temp.vl = INF;
			temp.is_end = false;
			adjlist.push_back(temp);
		}

		int i, j;
		int l;
		while (cin >> i >> j >> l)
		{
			if (i == -1)
				break;
			ArcNode s,t;
			s.adjvex = j;
			s.len = l;
			s.flag = false;
			t.adjvex = i;
			t.len = l;
			s.flag = false;
			++adjlist[i].out;
			++adjlist[j].in;
			adjlist[i].vout.push_back(s);
			adjlist[j].vin.push_back(t);
		}

	}

	void CPM()//若某条边ee=el,则为关键活动
	{

		if (!TopSort())
		{
			cout << "有回路" << endl;
			return;
		}

		if (!reTopSort())
		{
			cout << "有回路" << endl;
			return;
		}
		vector<int> sum;
		getee();
		getel();
		int s = 0;
		for (int i = 0; i < vertex_num; ++i)
		{
			list<ArcNode>::iterator it;
			for (it = adjlist[i].vout.begin(); it != adjlist[i].vout.end(); ++it)
				if (it->flag)
				{
					s += it->len;
					int k = it->adjvex;
					if (adjlist[k].is_end)
					{
						sum.push_back(s);
						s = 0;
					}
				}

		}
		for (size_t i = 0; i < sum.size(); ++i)
			if (s < sum[i])
				s = sum[i];
		cout << s << endl;

	}

private:
	std::vector<VertexNode<DataType>> adjlist;//顶点表
	int vertex_num;

	bool TopSort()//按拓扑排序求最早发生时间ve
	{
		list<int> S;//栈S
		int count = 0;
		for (int i = 0; i < vertex_num; ++i)//起点入栈
			if (adjlist[i].in == 0)
			{
				adjlist[i].ve = 0;//计算式ve[0]=0;
				S.push_front(i);
			}

		while (S.begin() != S.end())//栈非空时循环
		{
			int i = *(S.begin());
			S.pop_front();
			++count;
			list<ArcNode>::iterator it;
			for (it = adjlist[i].vout.begin(); it != adjlist[i].vout.end(); ++it)
			{
				int k = it->adjvex;
				if (adjlist[k].ve < (adjlist[i].ve + it->len))//计算式ve[k]=max{ve[j]+len<vj,vk>},j到k
					adjlist[k].ve = adjlist[i].ve + it->len;
				--adjlist[k].in;
				if (adjlist[k].in == 0)
					S.push_front(k);

			}

		}
		if (count < vertex_num)
			return false;
		else
			return true;

	}

	bool reTopSort()//按逆拓扑排序求最迟发生时间vl
	{
		list<int> S;//栈S
		int count = 0;
		for (int i = 0; i < vertex_num; ++i)//终点入栈
			if (adjlist[i].out == 0)
			{
				adjlist[i].vl = adjlist[i].ve;//算式vl[n-1]=ve[n-1]
				adjlist[i].is_end = true;
				S.push_front(i);			
			}

		while (S.begin() != S.end())//栈非空时循环
		{
			int i = *(S.begin());
			S.pop_front();
			++count;
			list<ArcNode>::iterator it;
			for (it = adjlist[i].vin.begin(); it != adjlist[i].vin.end(); ++it)
			{
				int k = it->adjvex;
				if (adjlist[k].vl > (adjlist[i].vl - it->len))//算式vl[k]=max{vl[j]-len<j,k>},j到k
					adjlist[k].vl = adjlist[i].vl - it->len;
				--adjlist[k].out;
				if (adjlist[k].out == 0)
					S.push_front(k);

			}

		}
		if (count < vertex_num)
			return false;
		else
			return true;
	}

	void getee()//由ve求ee
	{
		for (int i = 0; i < vertex_num; ++i)
		{
			list<ArcNode>::iterator it;
			for (it = adjlist[i].vout.begin(); it != adjlist[i].vout.end(); ++it)
			{
				it->ee = adjlist[i].ve;
			}
		}
	}

	void getel()//由vl求el
	{
		for (int i = 0; i < vertex_num; ++i)
		{
			list<ArcNode>::iterator it;
			for (it = adjlist[i].vin.begin(); it != adjlist[i].vin.end(); ++it)
			{
				it->el = adjlist[i].vl - it->len;
				int k = it->adjvex;
				list<ArcNode>::iterator t;
				for (t = adjlist[k].vout.begin(); t != adjlist[k].vout.end(); ++t)
					if (t->adjvex = i)
					{
						t->el = it->el;
						if (t->ee == t->el)
							t->flag = true;
						break;
					}
			}
		}
	}


};

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/ymwtz/article/details/43117231
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞