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

"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;
}


对任意给定的(顶点数不小于20,边数不少于30,的类型可以是有向、无向、有向网、无向网),能够输入的顶点和边(或弧)的信息,并存储到相应存储结构(邻接矩阵、邻接表、十字链表、邻接多重表,任选其中两种类型),对自己所创建的完成以下操作: 1、 对无向求每个顶点的度,或对有向求每个顶点的入度和出度(5分) 2、 完成插入顶点和边(或弧)的功能(5分) 3、 完成删除顶点和边(或弧)的功能(5分) 4、 两种存储结构的转换(5分),如果其中一种存储结构为十字链表或邻接多重表则增加5分。 5、 输出的深度优先遍历序列或广度优先遍历序列(5分) 6、 求的深度优先或广度优先的生成树(或生成森林)(存储结构为孩子-兄弟链表),并对生成树进行遍历(15分) 7、 判断的连通性,输出连通分量的个数(5分) 8、 判断中是否存在环,无向5分,有向10分 9、 给出顶点u和v,判断u到v是否存在路径(5分) 10、求顶点u到v的一条简单路径(10分) 11、求顶点u到v的所有简单路径(15分) 12、求顶点u到v的最短路径(10分) 13、求顶点u到其余各顶点的最短路径(15分) 14、求任两个顶点之间的最短路径(15分) 15、求最小生成树(15分) 16、对于有一个源点和一个汇点的有向网,求关键路径(20分)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值