关键路径(C语言 邻接表)

来源:互联网 发布:线切割报价软件 编辑:程序博客网 时间:2024/06/05 17:27

综述

一共四步

1、根据拓扑排序求ve

2、根据逆拓扑排序求vl

3、由ve求e,由vl求l

4、输出关键活动、权值

***************************************************************************************************************************

其中:

顶点对应事件发生,最早ve,最晚用vl

边对应活动开始,最早用e,最晚用l

求法

1、ve:ve[i] = max{ve[前]+边权}

              ve[0]=0

2、vl:vl[i] = min{vl[后]-边权}

             vl[最后]=ve[最后]

3、e:ve[前]

4、l:vl[后]-边权

***************************************************************************************************************************

关键路径

若额e[i] == l[i],则为关键活动

数据结构

//增加id用于标识边,与e和l数组下标对应//增加data记录边权值typedef struct Side//边{    int toVertex;//边指向的点    int data;    int id;    struct side *next;}Side,*sLink;typedef struct Vertex//顶点{    int data;    sLink first;//第一个边}Vertex,AdjList[20];typedef struct Graph//图{    AdjList adj;//顶点数组,注意不是指针,用.不用->    int n,v;//顶点数,边数}Graph,*gLink;

创建

//新增边的权值与idvoid createGraph(gLink g){    int n,v,data;    printf("请输入顶点数与边数");    scanf("%d %d",&n,&v);    g->n = n;    g->v = v;    int i;    for(i=0;i<n;i++)    {        printf("请输入顶点%d权值",i);        scanf("%d",&data);        g->adj[i].data = data;        g->adj[i].first = NULL;    }    printf("请输入边信息");    int v1,v2,da;    for(i=0;i<v;i++)    {        scanf("%d %d %d",&v1,&v2,&da);        sLink s = (sLink)malloc(sizeof(Side));        s->toVertex = v2;        s->next = g->adj[v1].first;        g->adj[v1].first = s;        s->data = da;        s->id = i;    }}

入度

void inDegree(gLink g,int *a){    int i;    for(i=0;i<g->n;i++)    {        a[i]=0;    }    for(i=0;i<g->n;i++)    {        sLink s = g->adj[i].first;        while(s)        {            a[s->toVertex]++;            s = s->next;        }    }}

全局变量

//全局变量int vers[15];//栈,装入拓扑排序,用于逆拓扑排序int top = -1;//栈指针//顶点-->事件发生:最早ve,最晚vl//边-->活动:最早e,最晚lint ve[15]={0},vl[15]={0},e[15]={0},l[15]={0};

拓扑排序求ve

//拓扑排序求vevoid tuopu(gLink g){    int queue[10];    int front=0, rear=0;    int a[g->n];    inDegree(g,a);    int i;    for(i=0;i<g->n;i++)    {        if(!a[i])        {            queue[rear++] = i;        }    }    while(front!=rear)    {        int v = queue[front++];        vers[++top] = v;//进栈        sLink s = g->adj[v].first;        while(s)        {            if(!--a[s->toVertex])            {                queue[rear++] = s->toVertex;            }            if(ve[v]+s->data>ve[s->toVertex]) ve[s->toVertex] = ve[v]+s->data;//为每一个后继顶点赋值ve            s = s->next;        }    }}

关键路径

//关键路径void path(gLink g){    //根据逆拓扑求vl    int i;    int v = vers[top--];    vl[v] = ve[v];    while(top!=-1)    {        v = vers[top--];//出栈        sLink s = g->adj[v].first;        vl[v]=vl[s->toVertex];        while(s)        {            if(vl[s->toVertex]-s->data<vl[v]) vl[v] = vl[s->toVertex]-s->data;//为每一个前驱顶点赋值vl            s = s->next;        }    }    //求e和l    //从顶点遍历,为每一个边确定e和l    for(i=0;i<g->n;i++)    {        sLink s = g->adj[i].first;        while(s)        {            e[s->id] = ve[i];//当前边e等于顶点ve            l[s->id] = vl[s->toVertex] - s->data;//当前边l等于指向顶点vl减去边权值            s = s->next;        }    }    //求关键路径    //输出关键活动和边的头顶点尾顶点    //e=l的边为关键活动    int j;    for(i=0;i<g->v;i++)    {        if(l[i]==e[i])        {            printf("a%-5d",i);            //遍历图,找到id为这个的边            for(j=0;j<g->n;j++)            {                sLink s = g->adj[j].first;                while(s)                {                    if(s->id==i)                    {                        printf("v%d-->v%d",j,s->toVertex);                        break;                    }                    s=s->next;                }            }            printf("\n");        }    }    //求总权值    //由于关键路径不一定只有一条    //所以从顶点开始,找到关键活动则跳到指向的下一个顶点,这样可以只得到一条关键路径    int quan = 0;    sLink s = g->adj[0].first;    while(s)    {        if(e[s->id]==l[s->id])        {            quan += s->data;            s = g->adj[s->toVertex].first;        }else        {            s = s->next;        }    }    printf("权值为:%d",quan);}

主函数

int main(){    gLink g = (gLink)malloc(sizeof(Graph));    createGraph(g);    tuopu(g);    path(g);    return 0;}

原创粉丝点击