数据结构_图_有向无环图应用之求关键路径

数据结构_图_有向无环图应用之求关键路径

head.h

#include<iostream>
#include<stack>
using namespace std;

#define MAX_VEX_NUM 20//最大节点数

class NextNode //存储弧节点相关信息//图以邻接表做存储结构
{
public:
	NextNode();
	int nextvex; //下一个节点的编号
	int weight; //弧上的权值
	NextNode *next;
};

NextNode::NextNode()
{
	nextvex = weight = 0;
	next = NULL;
}

class VexNode //节点信息
{
public:
	VexNode();
	char name; //节点名称
	int ve; //事件的最早发生时间
	int vl; //时间的最晚发生时间
	int indegree; //节点入度
	NextNode *firstnext; //指向存储以该节点做弧尾的弧的弧头顶点相关信息的节点
};

VexNode::VexNode()
{
	ve = vl = indegree = 0;
	firstnext = NULL;
}

class VexBox //顶点集合
{
public:
	VexBox();
	int vexnum; //定点数目
	VexNode vexbox[MAX_VEX_NUM]; //顶点集合
};

VexBox::VexBox()
{
	vexnum = 0;
}

class CriPath //Critical Path
{
public:
	void GetCriticalPath(); //接口函数
private:
	void GetVex(); //得到顶点信息
	void GetArc(); //得到弧的相关信息
	void GetVe(); //拓扑排序并求得事件的最早发生时间
	void GetLe(); //逆拓扑排序并求得事件的最晚发生时间
	void PrintCriPath(); //输出关键路径
	VexBox v; //顶点集合
	stack<int> s; //储存拓扑有序序列
	bool available; //标示该图是否是无环图
};

void CriPath::GetCriticalPath() //接口函数
{
	GetVex(); //得到顶点信息
	GetArc(); //得到弧的相关信息
	GetVe(); //拓扑排序并求得事件的最早发生时间
	GetLe(); //逆拓扑排序并求得事件的最晚发生时间
	PrintCriPath(); //输出关键路径
}

void CriPath::GetVex() //得到顶点信息
{
	cout << "Please Input The Name Of Each Vertex :" << endl << endl;
	char name;
	while (cin >> name)
	{
		v.vexbox[v.vexnum++].name = name;
	}
	cin.clear();
}

void CriPath::GetArc() //得到弧的相关信息
{
	cout << "Please Input The Information Of Eack Arc :" << endl
			<< "tail head weight" << endl;
	int tail, head, weight;
	NextNode *newnode, *p;
	while (cin >> tail >> head >> weight)
	{
		newnode = new NextNode;
		newnode->nextvex = head;
		newnode->weight = weight;
		v.vexbox[head].indegree++;
		if ((p = v.vexbox[tail].firstnext) == NULL)
		{
			v.vexbox[tail].firstnext = newnode;
		} //if
		else
		{
			while (p->next != NULL)
				p = p->next;
			p->next = newnode;
		} //else
	} //while
	cin.clear();
}

void CriPath::GetVe() //拓扑排序并求得事件的最早发生时间
{
	NextNode *p;
	bool find = false;
	int count = 0;
	while (1) //拓扑排序
	{
		for (int i = 0; i < v.vexnum; i++) //扫描所有节点
		{
			if (v.vexbox[i].indegree == 0) //如果入度为零
			{
				count++;
				find = true;
				s.push(i); //存储拓扑有序序列
				v.vexbox[i].indegree--;
				p = v.vexbox[i].firstnext;
				while (p != NULL)
				{
					if (v.vexbox[i].ve + p->weight > v.vexbox[p->nextvex].ve) //获得当前节点的ve
						v.vexbox[p->nextvex].ve = v.vexbox[i].ve + p->weight;
					v.vexbox[p->nextvex].indegree--;
					p = p->next;
				} //while
				break;
			} //if
		} //for
		if (find == true)
			find = false;
		else
			break;
	} //while
	if (count < v.vexnum) //判断图中是否存在环
	{
		cout << "There Are Cycle In This Graph ." << endl;
		available = false;
	}
	else
	{
		available = true;
	}
}

void CriPath::GetLe() //逆拓扑排序并求得事件的最晚发生时间
{
	if (available == true) //如果该图是无环图
	{
		NextNode *p;
		int node = s.top(); //处理汇点
		s.pop();
		v.vexbox[node].vl = v.vexbox[node].ve;
		while (!s.empty()) //处理拓扑有序序列中剩下的节点
		{
			node = s.top();
			s.pop();
			p = v.vexbox[node].firstnext;
			while (p != NULL) //获得当前节点的vl
			{
				if (v.vexbox[node].vl == 0)
					v.vexbox[node].vl = v.vexbox[p->nextvex].vl - p->weight;
				else if (v.vexbox[p->nextvex].vl - p->weight
						< v.vexbox[node].vl)
					v.vexbox[node].vl = v.vexbox[p->nextvex].vl - p->weight;
				p = p->next;
			} //while
		} //while
	} //if
}

void CriPath::PrintCriPath() //输出关键路径
{
	if (available == true) //如果该图是无环图
	{
		for (int i = 0; i < v.vexnum; i++)
		{
			if (v.vexbox[i].ve == v.vexbox[i].vl)
			//输出所有最早发生事件和最晚发生时间相同的点这些点构成了一条关键路径
			{
				cout << v.vexbox[i].name << endl;
			} //if
		} //for
	} //if
}

main.cpp

#include"head.h"
 
int main()
{
	CriPath cp;
	cp.GetCriticalPath();
	system("pause");
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注