图论 关键路径


测试所用的AOE图如下:



算法参考<大话数据>

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;

int stack2[100],top2;
int etv[100],ltv[100];

typedef struct NODE{
int adjvex;
int weight ;
NODE *next;
}Node;

typedef struct {
int in;
int data;
NODE *first;
}nodeList;

typedef struct {
int num_vex,num_edge;
int vex[100];
nodeList headvex[100];
}Graph;

int vis[100];//dfs使用

void create(Graph *g){
int i,j,k;
int x,y,z;
NODE *e;
scanf("%d%d",&g->num_vex,&g->num_edge);

for(i=0;i<g->num_vex;i++){
    scanf("%d",&g->headvex[i].data);
    g->headvex[i].in=0;
    g->headvex[i].first=NULL;
}

for(i=0;i<g->num_edge;i++)
{
    scanf("%d%d%d",&x,&y,&z);
    e=new NODE();
    e->weight=z;
    e->adjvex=y;
    e->next=g->headvex[x].first;//头插法插入新的结点
    g->headvex[x].first=e;
    g->headvex[y].in++;
}
memset(vis,0,sizeof(vis));//dfs使用
}
//建图时跟拓扑排序完全一样

void dfs(Graph *g,int x)
{
    vis[x]=1;
    NODE *p;
    int i,j;
    printf("%d ",g->headvex[x].data);
    p=g->headvex[x].first;
    while(p)
    {
        if(!vis[p->adjvex])
        {
            dfs(g,p->adjvex);
        }
        p=p->next;

    }
}
void  TopologicalSort(Graph *g){
  int mystack[100],top=0;
  //之所以用两个栈是因为,mystack这个栈用于前期拓扑排序,stack2这个栈用于保存进入mystack的元素
  //进入mystack栈是从头到尾,故stack2中的元素栈顶到栈底是从尾到头(栈的先进后出性质)
  top2=0;
  int Count=0;
  int i,gettop,k,j;
  NODE *e;
  for(i=0;i<g->num_vex;i++)
   {
       if(g->headvex[i].in==0)mystack[++top]=i;
   }//将入度为0的点首先入栈

   for(i=0;i<g->num_vex;i++)
        etv[i]=0;//etv数组初始化

  while(top!=0)
   {
       gettop=mystack[top--];
       stack2[++top2]=gettop;
       Count++;
       for(e=g->headvex[gettop].first;e;e=e->next)
       {
           g->headvex[e->adjvex].in--;
           if(g->headvex[e->adjvex].in==0)mystack[++top]=e->adjvex;
           //跟拓扑排序不同的就是多了下面这个if语句
           if(etv[gettop]+e->weight>etv[e->adjvex])
        etv[e->adjvex]=etv[gettop]+e->weight;
        //为什么是选大值?因为某个顶点的最早发生时间是在和他相关的活动必须全部完成之后
        //比如到V3点,那么v1 v2点的活动必须先完成,故取最大值12,这样v0 v1 v2的活动都完成了
       }
   }
/*用来测试etv数组
   for(i=0;i<g->num_vex;i++)
    printf("%d ",etv[i]);
   printf("\n");
*/
  //if(Count<g->num_vex)return 0;
  //else return 1;

}
void Critical(Graph *g)//求关键路径
{
NODE *e;
int i,j,k,gettop;
int ete,lte;

TopologicalSort(g);

for(i=0;i<g->num_vex;i++)//ltv数组初始化
ltv[i]=etv[g->num_vex-1];
//etv[g->num_vex-1]是所有活动最早完成的时间,ltv是从后向前找最晚开工的时间

while(top2!=0)
{
gettop=stack2[top2--];
for(e=g->headvex[gettop].first;e;e=e->next)
    {
        k=e->adjvex;//k是gettop这个点连接的下一个点
        if(ltv[k]-e->weight<ltv[gettop])
            ltv[gettop]=ltv[k]-e->weight;
            //从拓扑序列最后一个点开始推导
            //这里找的是最晚开工时间,为什么找的时候ltv要尽量小呢?
            //举个例子(和测试数据不相关):假如v6下面连着v7 v8 v9 ,而且将v6 v7 v8 v9 做完这个工程就算完事了
            // v6的初始值为tmp  ,v6 到v7 v8 v9 的值分别是10 12 14,那么v6的值应该为tmp-14,如果不是的话,那么v6这件事开始晚了,那么做完v9这件事就会延误工期

    }
}
for(j=0;j<g->num_vex;j++)
{
    for(e=g->headvex[j].first;e;e=e->next){
     k=e->adjvex;
     ete=etv[j];
     lte=ltv[k]-e->weight;
     if(ete==lte){
        printf("<%d,%d,%d>\n",g->headvex[j].data,g->headvex[k].data,e->weight);
        //输出关键路径
     }
    }
}
}

int main(){
Graph G;
create(&G);
//dfs(&G,0);//开始测试除了些问题,所以用dfs来检测建图是否正确
//printf("\n");
//TopologicalSort(&G);
Critical(&G);
return 0;
}
/*
10 13
0 1 2 3 4 5 6 7 8 9
0 1 3
0 2 4
1 3 5
2 3 8
2 5 7
1 4 6
3 4 3
4 6 9
4 7 4
5 7 6
6 9 2
7 8 5
8 9 3
*/




posted on 2017-09-19 23:08  横济沧海  阅读(205)  评论(0编辑  收藏  举报

导航