拓扑序和关键路径-笔记(.)

拓扑排序
概念
AOV网:顶点表示活动,弧表示活动先后关系的 有向图
结点表示事件,是时刻;

所以一个节点包含了: 
前一个活动的结束事件和下一个活动的开始事件

而弧表示过程,代表活动的持续时间
有某个集合上的一个偏序(<=关系)的到该集合上一个全序,该操作称为拓扑排序

拓扑排序-方法
(计算各顶点的入度, 将度为零的顶点入栈)
1 从图中没有前驱的顶点中选择一个并输出
(出栈,更新后继结点的入度,若入度为0,入栈)
2 从图中 删除此顶点 及所有从其出发的弧
3 重复上述两步,至图空 或图不空但不存在无前驱的顶点(好像有环的存在)
(根据输出的点数,判断是否存在闭环)

实现

Status TopologicalSort(ALGraph G)
{
	//indegree是个数组
	FindInDegree(G, indegree);
	InitStack(S);
	for (int i = 0; i <G.vexnum; i++)
		if (indegree[i] == 0) Push(S, i);
	cnt = 0;
	while (StackEmpty(S) == FALSE)
	{
		Pop(S, i);
		OutputElem(G.vertices[i].data);
		cnt++;
		for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc)
		{
			k = p->adjvex;
			indegree[k]--;
			if (indegree[k] == 0)
				Push(S, k);
		}
	}
	if (cnt < G.vexnum) 
		return ERROR;
	else 
		return OK;
}

关键活动
关键活动:必须在具备执行条件的第一时间启动活动,否则会导致延期
即保证工期前提下最早开始时间和最晚开始时间相同的活动
顶点状态最早/晚激活时间: ee(act) = ve(头) el(act) = vl(尾) - dur(act)

求顶点状态的最早激活时间
ve(源点) = 0
对于普通顶点v, 设W为其前驱顶点集W
//为什么要用max函数?
//因为 活动v 必须在前面所有准备活动都做好了之后可以激活
ve(v) = max(ve(w) + dut(w, v) | w ∈ W)

按照什么顺序来逐个计算各个顶点的最早激活时间?
感觉是按照拓扑序

按照拓扑序逐个计算,找各顶点的前驱不方便怎么办?
如求ve(e)可在处理b和c时及时更新保留最大
Status GetVEAndTvsTopOrd(AlGraph G, Stack &T)
{
	for (int i = 0; i < G.vexnum; i++)
		ve[i] = 0;
	FindInDegree(G, indegree);
	InitStack(S);
	//为了方便后面求个顶点最晚激活时间还要用栈T记录拓扑逆序
	InitStack(T);
	for (int i = 0; i < G.vexnum; i++)
		if (indegree[i] == 0)
			Push(S, i);
	cnt = 0;
	while (!StackEmpty(S))
	{
		Pop(S, j);
		Push(T, j);
		cnt++;
		for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
		{
			k = p->adjvex;
			indegree[k]--;
			if (indegree[k] == 0) Push(S, k);
			if (ve[j] + *(p->info) > ve[k])
				ve[k] = ve[j] + *(p->info);
		}
	}
	if (cnt < G.vexnum)
		return ERROR;
	else 
		return OK;
}
关键路径-方法-求顶点状态的最晚到达时间
vl(终点) = ve(终点)
对普通顶点v, 设W为其后继顶点的集合,则
//为了保证所有v后面的活动都能在ve(终点)之前完成
//所以要求出vl的最小值
vl(v) = min{vl(w) - dut(v,w) | w ∈ w}

按照什么顺序来逐个计算各个顶点的最完激活时间
拓扑逆序(T的出栈顺序,逐个元素根据其后继的ve值和弧权跟新)

初始化各顶点vl值为工期,按照拓扑逆序逐个节点更新其自身的vl值
根据当前元素的后继ve值和弧权更新
Status CriticalPath(ALGraph G)
{
	InitStack(T);
	if (!GetVEAndTvsTopOrd(G, T))
		return ERROR;
	for (int i = 0; i < G.vexnum; i++)
		vl[i] = ve[i];
	while (StackEmpty(T) == FALSE)
	{
		Pop(T, j);
		for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
		{
			k = p->adjvex;
			dur = *(p->info);
			if (vl[k] - dut < vl[j])
				vl[j] = vl[k] - dut;
		}
	}
	for (j = 0; j < G.vexnum; j++)
	{
		for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
		{
			k = p->adjvex;
			dut = *(p->info);
			ee = ve[j];
			el = vl[k] - dut;
			if (ee == el)
				printf("critical actv\n");
			else 
				printf("no critical actv\n");
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值