关键路径代码

#define _CRT_SECURE_NO_WARNINGS

#define MAXSIZE 100

#define MAX_VERTEX_NUM 20//最大顶点个数

#define VertexType int//顶点数据类型

#include <stdio.h>

#include <stdlib.h>

//#include<string>

//#include<cstring>

typedef enum { false, true } bool;

 

/*创建图的邻接表*/

typedef struct ArcNode {

   int adv;//指向顶点的位置

   struct ArcNode* nextArc;//指向下一条边

   int w;//表示权值

}ArcNode;

 

typedef struct VNode {

   ArcNode* first;//指向该顶点第一条弧的指针

   VertexType datam; //顶点数据

}AdVlist;

 

typedef struct ALGraph {

   AdVlist vts[500];//顶点向量

   int v, e;//顶点个数,边的个数

}ALGraph;

 

/*查找输入的x顶点位置*/

int Find(ALGraph g, VertexType x) {

   for (int i = 0; i < g.v; i++) {

       if (x == g.vts[i].datam) return i;

   }

   return -1;

}

 

int ve[500];//全局变量,表示事件最早发生的时间

//stack<int> t;//t为返回拓扑序列的栈

//定义栈

 

typedef struct stack {

   VertexType data;

   struct stack* next;

}stack;

stack* t;

//初始化栈结构

void initStack(stack** t) {

   (*t) = (stack*)malloc(sizeof(stack));

   if (*t != NULL) {

       (*t)->next = NULL;

   }

   return 0;

}

//判断栈是否为空

bool StackEmpty(stack t) {

   if (t.next == NULL) {

       return true;

   }

   return false;

}

//进栈,头插法将新节点插入链表

void push(stack* t, VertexType u) {

   stack* p = (stack*)malloc(sizeof(stack));

   if (p != NULL) {

       p->data = u;

       p->next = NULL;

       p->next = t->next;

       t->next = p;

   }

}

//出栈,删除链表首元结点,释放空间,并将改节点的数据域通过地址传递给变量i

void pop(stack* t, VertexType* i) {

   stack* p = t->next;

   *i = p->data;

   t->next = t->next->next;

   free(p);

}

 

/*创建图*/

void Creat(ALGraph g) {

   int mw, edge = 0;

   int v1, v2;

   printf("输入图的顶点数\n");

   scanf("%d", &g.v);

   printf("输入图中结点信息\n");

   //输入顶点的信息,并且使指边指向NULL

   for (int i = 0; i < g.v; i++) {

       scanf("%d", &g.vts[i].datam);

       g.vts[i].first = NULL;

   }

   printf("输入图中两个顶点(起点和终点)与相应的权值,其中(0,0,0)结束\n");

   while (1) {

       scanf("%d%d%d", &v1, &v2, &mw);

       if (v1 == "0" && v2 == "0" && mw == 0) break;

       edge++;

       int j, k;

       j = Find(g, v1);

       k = Find(g, v2);

       ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));//分配空间 //ArcNode* p1 = new ArcNode;

       //使边p的顶点指向第k个顶点,意思就是第k个顶点为指向量,例如边<i,j>,则j就是这里的k

       p1->adv = k;

       //使边p的权值赋值

       p1->w = mw;

       p1->nextArc = NULL;

       p1->nextArc = g.vts[j].first;

       g.vts[j].first = p1;

   }

   g.e = edge;

}

/*求各顶点的入度,保存在indegree数组中*/

void FindID(ALGraph g, int indegree[500]) {

   int i;

   ArcNode* p;

   for (i = 0; i < g.v; i++) indegree[i] = 0;//初始化初始值全为0

   for (i = 0; i < g.v; i++) {

       p = g.vts[i].first;//p是第i个顶点指向的第一条边的指针

       //遍历第i个顶点所有的边,直到指向NULL

       while (p != NULL) {

           indegree[p->adv]++;//边的顶点,就是此时的顶点入度+1

           p = p->nextArc;//遍历

       }

   }

}

 

/*拓扑排序*/

bool TopOrder(ALGraph g) {

   stack *s;//s为存放入度为0的顶点的栈

   initStack(&s);

   int count, i, j, k;//count做检验工作,因为入度为0的时候可能会有顶点没有进入,这样做更加保险

   ArcNode* p;

   int indegree[500];//各顶点的入度

   FindID(g, indegree);

   for (i = 0; i < g.v; i++) {

       if (indegree[i] == 0) push(s,i);//使没有入度的点入栈,就是说在拓扑排序中,先寻找入度为0的顶点

   }

   count = 0;

   for (i = 0; i < g.v; i++) {

       ve[i] = 0;//初始化最早发生的时间

   }

   while (!StackEmpty(*s)) {

       /*如果栈s非空,那么先出栈并赋值给j,然后使j进入栈t,这样栈t就是拓扑序列,因为s里面的肯定是入度为0的了*/

       j = s->data;

       pop(s,j);

       push(t,j);

       count++;

       //边p指向顶点j的第一条边

       p = g.vts[j].first;

       while (p != NULL) {

           k = p->adv;

           /*顶点k(就是这条边的指向顶点)度数是否为0,如果不是那么减为0,然后使其入栈*/

           if (!(--indegree[k])) push(s,k);

           //j的最早发生事件+权值是否大于这个顶点的ve,注意一开始ve(0)=0

           if (ve[j] + p->w > ve[k]) ve[k] = ve[j] + p->w;

           p = p->nextArc;

       }

   }

   if (count < g.v) return false;//有回路

   else return true;

}

 

/*关键路径算法

   有了最早发生事件了,就是全局变量ve,然后现在要求最晚发生时间了,最后可求出活动的时间

   关键路径就是活动,注意是活动(也就是边)最早和最晚时间发生的活动

*/

bool CriticalPath(ALGraph g) {

   ArcNode* p;

   int i, j, k, dut, ei, li;

   int vl[500];//vl为事件,不是活动,发生的最晚时间

   //TopOrder(g);

   if (!TopOrder(g)) return false;

   for (i = 0; i < g.v; i++) vl[i] = ve[g.v - 1];//初始化

   /*按逆拓扑顺序求各顶点的vl*/

   while (!StackEmpty(*t)) {

       j = t->data;

       pop(t,j);

       p = g.vts[j].first;

       while (p != NULL) {

           k = p->adv;

           dut = p->w;

           if (vl[k] - dut < vl[j]) vl[j] = vl[k] - dut;

           p = p->nextArc;

       }

   }

   

   for (j = 0; j < g.v; j++) {

       p = g.vts[j].first;

       while (p != NULL) {

           k = p->adv;

           dut = p->w;

           ei = ve[j];

           li = vl[k] - dut;

           if (ei == li)

               printf("关键路径\n");

               printf( "Initial  End  Weight  el  vl\n");

               printf(g.vts[j].datam, g.vts[k].datam, dut);

              // cout << g.vts[j].datam << " " << g.vts[k].datam << " " << dut << endl;

           p = p->nextArc;

       }

   }

   return true;

}

 

 

 

int main() {

   ALGraph g;

   Creat(g);

   CriticalPath(g);

   return 0;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值