typedef struct ArcNode {
int adjvex; // 该边所指向的顶点的序号
struct ArcNode *nextarc; // 指向下一条边的指针
int weight; // 边的权值
} ArcNode; // 弧边的节点结构
typedef struct {
int data; // 顶点信息
int inDegree; // 顶点的入度
ArcNode *firstarc; // 指向第一条依附该点的边的指针
} AdjList[9]; // 定点的节点结构
typedef struct {
AdjList adjList; //
int vexnum, arcnum; // 图当前的顶点数和边数
} Graph;//图的结构定义
//region AOV AOE
/**
* 拓扑排序 A0V网
* AOV(有向图):用顶点表示活动,用弧边表示优先关系;图中没有环
* 算法步骤:
* 1.栈初始化,累加器count初始化
* 2.扫描顶点表,将没有入度的顶点加入栈中
* 3.当栈非空时,循环
* 3.1.退出栈顶元素,累加器+1
* 3.2.将退出的栈顶元素的各个邻接点的入度-1
* 3.3.将退出后的度为0的顶点,加入栈中
* 可以用于判断图中有没有环
* 即 count ?= g->vexnum
* @param g
*/
void TopoSort(Graph *g) {
// 栈初始化,累加器count初始化
int count = 0;
Stack *stack = NULL;
stack = initStack(stack);
//扫描顶点表,将没有入度的顶点加入栈中
for (int i = 0; i < g->vexnum; ++i) {
if (g->adjList[i].inDegree == 0) {
enStack(stack, g->adjList[i].data);
}
}
ArcNode *arc = NULL;
printf("拓扑排序:");
//当栈非空时,循环
while (!isEmptyStack(stack)) {
// 退出栈顶元素,累加器+1
int vex = deStack(stack);
count++;
printf("%2d", g->adjList[vex].data);
//将退出的栈顶元素的各个邻接点的入度-1
arc = g->adjList[vex].firstarc;
while (arc) {
g->adjList[arc->adjvex].inDegree -= 1;
//将退出后的度为0的顶点,加入栈中
if (g->adjList[arc->adjvex].inDegree == 0) {
enStack(stack, g->adjList[arc->adjvex].data);
}
arc = arc->nextarc;
}
}
if (count < g->vexnum) {
printf("\n图中存在环");
} else {
printf("\n不存在环");
}
}
/**
* 关键路径 AOE网
* AOE(带权的有向图):用顶点表示事件,用弧边表示活动,用权值表示活动的时间。不存在环
* @return
*/
void KeyPath(Graph *g) {
// 拓扑排序
int topo[g->vexnum];
int ve[g->vexnum]; // 事件最早发生时间数组
int vl[g->vexnum]; // 事件最晚发生时间数组
int count = 0;
Stack *stack = NULL;
stack = initStack(stack);
//扫描顶点表,将没有入度的顶点加入栈中
for (int i = 0; i < g->vexnum; ++i) {
ve[i] = 0;
if (g->adjList[i].inDegree == 0) {
enStack(stack, g->adjList[i].data);
}
}
ArcNode *arc = NULL;
while (!isEmptyStack(stack)) {
int vex = deStack(stack);
topo[count++] = vex;
arc = g->adjList[vex].firstarc;
while (arc) {
if ((--(g->adjList[arc->adjvex].inDegree)) == 0) {
enStack(stack, arc->adjvex);
}
int start = vex; // 边的起始点
int end = g->adjList[arc->adjvex].data; // 边的终点
// 更新ve数组 start + arc_weight > end
if (ve[start] + arc->weight > ve[end]) { // 选择最大的
ve[end] = ve[start] + arc->weight;
}
arc = arc->nextarc;
}
}
if (count < g->vexnum) {
printf("存在环\n");
return;
}
printf("topo:");
for (int i = 0; i < g->vexnum; ++i) {
printf("%4d", topo[i]);
}
printf("\nve:");
for (int i = 0; i < g->vexnum; ++i) {
printf("%4d", ve[i]);
}
// 初始化vl数组 即结束点的ve值,这个ve值为最大值
for (int i = 0; i < g->vexnum; ++i) {
vl[i] = ve[count - 1];
}
// 计算vl数组
while (count != 0) {
int start = topo[--count]; // 把拓扑序列作为栈,
arc = g->adjList[start].firstarc; // 当前顶点的邻接点头指针
while (arc) {
int end = arc->adjvex; // 边的终点
//更新vl数组=min{ vl[end]-len<start, end> },len是weight
if (vl[start] > vl[end] - arc->weight) { // 选择最小的
vl[start] = vl[end] - arc->weight;
}
arc = arc->nextarc;
}
}
printf("\nvl:");
for (int i = 0; i < g->vexnum; ++i) {
printf("%4d", vl[i]);
}
printf("\n关键路径:\n");
// 计算关键路径
for (int i = 0; i < g->vexnum; ++i) {
arc = g->adjList[i].firstarc;
while(arc){
int start = g->adjList[i].data; // 起始节点
int end = g->adjList[arc->adjvex].data; // 终止节点
int ee = ve[start]; // 计算活动的最早开始事件ee,与当前边起点的ve值相同
int el = vl[end] - arc->weight; // 计算活动的最晚开始时间,为当前边的终点的vl值-边的权值
if(el == ee){ // 相等则是关键路径
printf("(%d, %d)->%d\n", start, end, arc->weight);
}
arc = arc->nextarc;
}
}
}
基于邻接表的AOV,AOE。拓扑排序和关键路径
最新推荐文章于 2024-11-12 09:58:04 发布