在有一堆有先后制约的任务,每个任务需要使用一定的时间完成
四个描述量
ve(vj)–表示事件vj的最早发生时间 ve(v1)=0 ve(v2)=30
vl(vj)–表示事件vj最迟发生事件 vl(v4)=165
e(i) –表示活动ai的最早开始时间 e(C)=30
l(i)–表示活动ai的最迟开始时间 l(C)=120
l(i)-e(i)–表示完成活动ai的时间余量
关键活动
–关键路径上的活动,l(i)==e(i)的活动
weight
vi—->vj
e=ve[i] ; l=vl[j]-weight ;
1、求ve(i)、vl(j)
2、求e(i)、l(i)
3、计算l(i)-e(i)
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
const int MaxVnum = 100; //顶点数最大值
int indegree[MaxVnum]; //入度数组
int ve[MaxVnum]; //事件vi的最早发生时间
int vl[MaxVnum]; //事件vi的最迟发生时间
typedef string VexType; //顶点的数据类型为字符型
typedef struct AdjNode
{ //定义邻接点类型
int v; //邻接点下标
int weight; //权值
struct AdjNode *next; //指向下一个邻接点指针
} AdjNode;
typedef struct VexNode
{ //定义顶点类型
; // VexType为顶点的数据类型,根据需要定义
VexType data*first; //指向第一个邻接点指针
AdjNode } VexNode;
typedef struct
{ //包含邻接表和逆邻接表
[MaxVnum]; //定义邻接表
VexNode Vex[MaxVnum]; //定义逆邻接表
VexNode converse_Vexint vexnum, edgenum; //顶点数,边数
} ALGragh;
int locatevex(ALGragh G, VexType x)
{
for (int i = 0; i < G.vexnum; i++) //查找顶点信息的下标
if (x == G.Vex[i].data)
return i;
return -1; //没找到
}
void insertedge(ALGragh &G, int i, int j, int w) //插入一条边
{
*s1, *s2;
AdjNode //创建邻接表结点
= new AdjNode;
s1 ->v = j;
s1->weight = w;
s1->next = G.Vex[i].first;
s1.Vex[i].first = s1;
G//创建逆邻接表结点
= new AdjNode;
s2 ->v = i;
s2->weight = w;
s2->next = G.converse_Vex[j].first;
s2.converse_Vex[j].first = s2;
G}
void printg(ALGragh G) //输出邻接表
{
<< "----------邻接表如下:----------" << endl;
cout for (int i = 0; i < G.vexnum; i++)
{
*t = G.Vex[i].first;
AdjNode << G.Vex[i].data << ": ";
cout while (t != NULL)
{
<< "[" << t->v << " " << t->weight << "] ";
cout = t->next;
t }
<< endl;
cout }
<< "----------逆邻接表如下:----------" << endl;
cout for (int i = 0; i < G.vexnum; i++)
{
*t = G.converse_Vex[i].first;
AdjNode << G.converse_Vex[i].data << ": ";
cout while (t != NULL)
{
<< "[" << t->v << " " << t->weight << "] ";
cout = t->next;
t }
<< endl;
cout }
}
void CreateALGraph(ALGragh &G) //创建有向图的邻接表和逆邻接表
{
int i, j, w;
, v;
VexType u<< "请输入顶点数和边数:" << endl;
cout >> G.vexnum >> G.edgenum;
cin << "请输入顶点信息:" << endl;
cout for (i = 0; i < G.vexnum; i++) //输入顶点信息,存入顶点信息数组
{
>> G.Vex[i].data;
cin .converse_Vex[i].data = G.Vex[i].data;
G.Vex[i].first = NULL;
G.converse_Vex[i].first = NULL;
G}
<< "请依次输入每条边的两个顶点及权值u,v,w" << endl;
cout while (G.edgenum--)
{
>> u >> v >> w;
cin = locatevex(G, u); //查找顶点u的存储下标
i = locatevex(G, v); //查找顶点v的存储下标
j if (i != -1 && j != -1)
(G, i, j, w);
insertedgeelse
{
<< "输入顶点信息错!请重新输入!" << endl;
cout .edgenum++; //本次输入不算
G}
}
}
void FindInDegree(ALGragh G) //求出各顶点的入度存入数组indegree中
{
int i, count;
for (i = 0; i < G.vexnum; i++)
{
= 0;
count *p = G.converse_Vex[i].first;
AdjNode if (p)
{
while (p)
{
= p->next;
p ++;
count}
}
[i] = count;
indegree}
<< "入度数组为:" << endl;
cout for (int i = 0; i < G.vexnum; i++) //输出入度数组
<< indegree[i] << "\t";
cout << endl;
cout }
bool TopologicalSort(ALGragh G, int topo[]) //拓扑排序
{
//有向图G采用邻接表存储结构
//若G无回路,则生成G的一个拓扑序列topo[]并返回true,否则false
int i, m;
<int> S; //初始化一个栈S,需要引入头文件#include<stack>
stack(G); //求出各顶点的入度存入数组indegree[]中
FindInDegreefor (i = 0; i < G.vexnum; i++)
if (!indegree[i]) //入度为0者进栈
.push(i);
S= 0; //对输出顶点计数,初始为0
m while (!S.empty()) //栈S非空
{
= S.top(); //取栈顶顶点i
i .pop(); //栈顶顶点i出栈
S[m] = i; //将i保存在拓扑序列数组topo中
topo++; //对输出顶点计数
m*p = G.Vex[i].first; // p指向i的第一个邻接点
AdjNode while (p) // i的所有邻接点入度减1
{
int k = p->v; // k为i的邻接点
--indegree[k]; // i的每个邻接点的入度减1
if (indegree[k] == 0) //若入度减为0,则入栈
.push(k);
S= p->next; // p指向顶点i下一个邻接结点
p }
(G);
printg}
if (m < G.vexnum) //该有向图有回路
return false;
else
return true;
}
bool CriticalPath(ALGragh G, int topo[]) // G为邻接表存储的有向网,输出G的各项关键活动
{
int n, i, k, j, e, l;
if (TopologicalSort(G, topo))
{
<< "拓扑序列为:" << endl;
cout for (int i = 0; i < G.vexnum; i++) //输出拓扑序列
<< topo[i] << "\t";
cout << endl;
cout }
else
<< "该图有环,无拓扑序列!" << endl;
cout = G.vexnum; // n为顶点个数
n for (i = 0; i < n; i++) //给每个事件的最早发生时间置初值0
[i] = 0;
ve//按拓扑次序求每个事件的最早发生时间
(G);
printgfor (i = 0; i < n; i++)
{
= topo[i]; //取得拓扑序列中的顶点序号k
k *p = G.Vex[k].first; // p指向k的第一个邻接顶点
AdjNode while (p != NULL)
{ //依次更新k的所有邻接顶点的最早发生时间
= p->v; // j为邻接顶点的序号
j if (ve[j] < ve[k] + p->weight) //更新顶点j的最早发生时间ve[j]
[j] = ve[k] + p->weight;
ve= p->next; // p指向k的下一个邻接顶点
p }
}
for (i = 0; i < n; i++) //给每个事件的最迟发生时间置初值ve[n-1]
[i] = ve[n - 1];
vl//按逆拓扑次序求每个事件的最迟发生时间
for (i = n - 1; i >= 0; i--)
{
= topo[i]; //取得逆拓扑序列中的顶点序号k
k *p = G.Vex[k].first; // p指向k的第一个邻接顶点
AdjNode while (p != NULL)
{ //根据k的邻接点,更新k的最迟发生时间
= p->v; // j为邻接顶点的序号
j if (vl[k] > vl[j] - p->weight) //更新顶点k的最迟发生时间vl[k]
[k] = vl[j] - p->weight;
vl= p->next; // p指向k的下一个邻接顶点
p }
}
<< "事件的最早发生时间和最迟发生时间:" << endl;
cout for (int i = 0; i < n; i++)
<< ve[i] << "\t" << vl[i] << endl;
cout
//判断每一活动是否为关键活动
<< "关键活动路径权值之和为:" << vl[n - 1] << endl;
cout << endl;
cout << "关键活动路径为:";
cout for (i = 0; i < n; i++) //每次循环针对vi为活动开始点的所有活动
{
*p = G.Vex[i].first; // p指向i的第一个邻接顶点
AdjNode while (p != NULL)
{
= p->v; // j为i的邻接顶点的序号
j = ve[i]; //计算活动<vi, vj>的最早开始时间e
e = vl[j] - p->weight; //计算活动<vi, vj>的最迟开始时间l
l if (e == l) //若为关键活动,则输出<vi, vj>
<< "<" << G.Vex[i].data << "," << G.Vex[j].data << "> ";
cout = p->next; // p指向i的下一个邻接顶点
p }
}
return true;
}
int main()
{
;
ALGragh Gint *topo = new int[G.vexnum];
(G); //创建有向图的邻接表和逆邻接表
CreateALGraph(G); //输出邻接表和逆邻接表
printg(G, topo);
CriticalPathreturn 0;
}