关键路径问题

问题描述:一个工程上的关键活动直接影响着整个工程的进展情况,要求实现关键路径上问题的求解。
例图:

输入示例:

//9 11
//V1 V2 V3 V4 V5 V6 V7 V8 V9
//a3 1 4 5   a2 1 3 4   a1 1 2 6   a4 2 5 1   a5 3 5 1   a6 4 6 2   a8 5 8 7   a7 5 7 9   a9 6 9 4   a10 7 9 2   a11 8 9 4

存储结构(邻接表):

typedef struct ArcNode {
	string arcName;	//弧的名称
	int adjvex;	//弧的邻接点位置
	struct ArcNode *nextarc;	//指向下一条弧的指针
	InfoType info;	//弧长
	int ee;//活动最早开始时间
	int el;//活动最晚开始时间
}ArcNode;
typedef struct VNode {
	VertexType vName;	//顶点名称
	ArcNode *firstarc;	//指向第一条依附该顶点的弧的指针
}Vnode;
typedef struct {
	VNode vertices[MAX_VERTEX_NUM];//顶点数组
	int vexnum, arcnum;	//图的当前顶点数和弧数
}ALGraph;

 求拓扑序列函数:

Status TopologicalOrder(ALGraph G, stack<int> &T) {
	//求各事件的最早发生时间ve
	//T为拓扑序列顶点栈,S为零入度顶点栈
	//若G无回路,则用栈T返回G的一个拓扑序列,且函数返回值为OK,否则为ERROR

	//对各顶点求入度indegree[0..vernum-1]
	FindInDegree(G, indegree);	
	stack<int> S;//建立零点入度栈S
	for (int i = 0; i < G.vexnum; i++)
		if (!indegree[i])
			S.push(i);		
	//工程起始点入栈
	int count = 0;
	for (int i = 0; i < G.vexnum; i++)
		ve[i] = 0;//事件最早发生时间初始化
	
	while (!S.empty()) {
		//入度为零的点最先输出,并将其所有邻接点入度减一,更新事件最早发生时间
		int j = S.top();
		S.pop();
		T.push(j);
		++count;
		for (ArcNode *p = G.vertices[j].firstarc; p; p = p->nextarc) {
			int k = p->adjvex;
			if (--indegree[k] == 0) 
				S.push(k);	
			//若入度减为0,则入栈
			if (ve[j] + p->info > ve[k])	
				ve[k] = ve[j] + p->info;
			//p->info=dut(<j,k>)
		}
	}
	if (count < G.vexnum) {
		return ERROR;
	}
	else
		return OK;
}

 求关键路径函数:

Status CriticalPath(ALGraph G) {
	//若图中有回路,程序结束
	stack<int> T;
	if (!TopologicalOrder(G, T)) {
		cout << "有回路!" << endl;
		return ERROR;
	}
	//初始化顶点事件最迟发生时间
	for (int i = 0; i < G.vexnum; i++)
		vl[i] = ve[G.vexnum-1];
	//按拓扑逆序列求各顶点的vl值
	while (!T.empty()) {			
		int j = T.top();
		T.pop();
		for (ArcNode *p = G.vertices[j].firstarc; p; p = p->nextarc){
			int k = p->adjvex;
			int dut = p->info;
			if (vl[k] - dut < vl[j])
				vl[j] = vl[k] - dut;
		}
	}
	//遍历所有的边,求出活动发生的最早时间和最晚时间
	for (int j = 0; j < G.vexnum; j++)
		for (ArcNode *p = G.vertices[j].firstarc; p; p = p->nextarc) {
			int k = p->adjvex;
			int dut = p->info;
			p->ee = ve[j];
			p->el = vl[k] - dut;
		}
	return OK;
}

求入度函数:

void FindInDegree(ALGraph G,int *indegree){
	for (int i = 0; i < G.vexnum; i++)
		indegree[i] = 0;
	for (int j = 0; j < G.vexnum; j++)
		for (ArcNode *p = G.vertices[j].firstarc; p; p = p->nextarc)//遍历所有的边
			++indegree[p->adjvex];//边的邻接点的度加一
}

图的创建函数:

void CreateGraph(ALGraph &G) {
	cout << "------------------请输入顶点个数,活动个数:-------------------" << endl;
	cin >> G.vexnum >> G.arcnum;
	
	cout << "-------------------请输入" << G.vexnum << "个顶点的名称:----------------------" << endl;
	for (int i = 0; i < G.vexnum; i++) {
		cin >> G.vertices[i].vName;
		G.vertices[i].firstarc = NULL;
	}

	int startPoint, terminalPoint;//边的起点和终点
	cout << "-------请输入" << G.arcnum << "条边的名称,起始点编号,终止点编号,权值:--------" << endl;
	for (int j = 0; j < G.arcnum; j++) {
		ArcNode *p = NULL;//边结点初始化
		int length;//边的权值
		string arcname;
		cin >> arcname >> startPoint >> terminalPoint >> length;
		if(startPoint<1 || startPoint>G.vexnum || terminalPoint<1 || terminalPoint>G.vexnum) {
			cout << "!输入超出顶点编号范围!请重新输入:" << endl;
			exit(0);
		}
		startPoint--;//减一后变为下标
		terminalPoint--;
		p = new ArcNode;
		if (!p) {
			cout << "申请空间失败!" << endl;
			exit(0);
		}
		p->arcName = arcname;
		p->info = length;
		p->adjvex = terminalPoint;
		//倒插法,输入各顶点的邻接边时倒序输入
		p->nextarc = G.vertices[startPoint].firstarc;
		G.vertices[startPoint].firstarc = p;
	}
	cout << "----------------------------输入完成-------------------------" << endl << endl;
}

图的销毁函数:

void DestroyGraph(ALGraph &G) {
	ArcNode *p,*q;
	for (int i = 0; i < G.vexnum; i++) {
		p = G.vertices[i].firstarc;
		while (p) {
			q = p;
			p = p->nextarc;
			free(q);
		}
	}
	G.arcnum = 0;
	G.vexnum = 0;
}

输出函数:

void PrintGraph(ALGraph G) {
	cout << endl;
	cout << "                             结果 " << endl;
	cout << "--------------------------------------------------------------" << endl;
	cout << setw(6) << "顶点" << setw(6) << "ve" << setw(6) << "vl" << endl;
	cout << "--------------------------------------------------------------" << endl;
	for (int i = 0; i < G.vexnum; i++) {
		cout << setw(6) << G.vertices[i].vName;
		cout << setw(6) << ve[i];
		cout << setw(6) << vl[i];
		cout << endl;
	}
	cout << "--------------------------------------------------------------" << endl;
	cout << setw(6) << "活动" << setw(13) << "起始点" << setw(6) << "时间" << setw(6) << "e" << setw(6) << "l" << setw(10) << "关键活动" << endl;
	cout << "--------------------------------------------------------------" << endl;
	for (int j = 0; j < G.vexnum; j++)
		for (ArcNode *p = G.vertices[j].firstarc; p; p = p->nextarc) {
			int k = p->adjvex;
			cout << setw(6) << p->arcName;
			cout << setw(6) << G.vertices[j].vName << "---->" << G.vertices[k].vName;
			cout << setw(6) << p->info;
			cout << setw(6) << p->ee;
			cout << setw(6) << p->el;
			//如果活动最早发生时间等于最晚发生时间,则其为关键活动
			int flag = (p->ee == p->el) ? 1 : 0;
			if (flag)
				cout << setw(10) << "是" << endl;
			else
				cout << setw(10) << "否" << endl;
		}
	cout << "--------------------------------------------------------------" << endl;
}

运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值