#include <stdio.h>

#include <string.h>

#include <stdlib.h>


#define Maxv 50

#define Maxvexnum 100

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define OVERFLOW -2

#define Sinitsize 100  //栈存储空间初始分配

#define Sincrement 50 //栈存储空间分配增


int ve[Maxvexnum];//存放最早发生时间


typedef char Vertextype[Maxv]; //顶点向量

typedef int  Selemtype;

typedef int  Status;

/*

www.quzhuanpan.comp

解释权来自去转盘网,转载请告知

*/

typedef struct Arcnode

{

    int adjvex;    //该弧所指向的顶点的位置

    struct Arcnode *nextarc;  //指向下一条弧的指针

    int weight;

} Arcnode; //储弧的信息存


typedef struct

{

    Vertextype data;    //顶点信息

    Arcnode *firstarc;  //第一个表结点的地址,指向第一条依附该顶点的弧的指针

} Vnode,Adjlist[Maxvexnum]; //头结点


typedef struct

{

    Adjlist vertexs;

    int vexnum,arcnum;

} Algraph;

/*

www.quzhuanpan.comp

解释权来自去转盘网,转载请告知

*/

typedef struct

{

    Selemtype *base;

    Selemtype *top;

    int stacksize;

} Sqstack;


int Locatevex(Algraph &G,Vertextype u)//字符型的u

{

    int i;

    for(i = 0; i < G.vexnum; ++i)

        if(strcmp(u,G.vertexs[i].data) == 0)

            return i;

    return OK;

}//all right


/*Status Listinsert(Algraph &G,int i,Arcnode *e) //在不带头结点的单链表L中第i个位置之前插入元素e

{


    e->nextarc =&L;

    L =*e;

    return OK;

}*/


int Creategraph(Algraph &G)

{

    int i,j,k,w;

    Vertextype V1,V2;

    Arcnode *e;

    printf("请输入图的顶点数,边数(以空格作为间隔):\n");

    scanf("%d%d",&G.vexnum,&G.arcnum);

    printf("请输入%d个顶点的值(小于%d个字符):\n",G.vexnum,Maxv);

    for(i = 0; i<G.vexnum; ++i) //构造顶点向量并初始化

    {

        scanf("%s",G.vertexs[i].data);

        G.vertexs[i].firstarc = NULL;

    }


    printf("请输入%d条弧的弧尾,弧头和权值(以空格作为间隔):\n",G.arcnum);

    for(k = 0; k < G.arcnum; ++k)

    {

        scanf("%s%s%d",V1,V2,&w);

        i = Locatevex(G,V1);

        j = Locatevex(G,V2);

        e = (Arcnode *)malloc(sizeof(Arcnode)); //:为每条弧分配内存,插入链表

        e->weight = w;

        e->adjvex = j;

        e->nextarc = NULL;

        //Listinsert(G.vertexs[i].firstarc,1,&e);

        e->nextarc=G.vertexs[i].firstarc;

        G.vertexs[i].firstarc=e;

    }

    return OK;

}

/*

www.quzhuanpan.comp

解释权来自去转盘网,转载请告知

*/

int Display(Algraph &G)

{

    int i;

    Arcnode *p;

    printf("\n\n");

    printf("%d个顶点:",G.vexnum);

    for(i = 0; i < G.vexnum; ++i)

    {

        printf("%s  ",G.vertexs[i].data);

    }


    printf("\n\n\n");


    printf("%d条弧:\n",G.arcnum);


    for(i = 0; i < G.vexnum; ++i)

    {

        p = G.vertexs[i].firstarc;

        while(p)

        {

            printf("%5s%5s%5d\n",G.vertexs[i].data,G.vertexs[p->adjvex].data,p->weight);

            p = p->nextarc;

        }


    }

    return OK;

}


void Findindegree(Algraph &G,int indegree[])

{

    int i;

    Arcnode *p;

    for(i = 0; i < G.vexnum; ++i)

        indegree[i] = 0;

    for(i = 0; i < G.vexnum; ++i)

    {

        p = G.vertexs[i].firstarc;

        while(p)

        {

            indegree[p->adjvex]++;

            p = p->nextarc;

        }

    }

}


void Initstack(Sqstack &S)

{

    S.base = (Selemtype *)malloc(Sinitsize * sizeof (Selemtype));

    if(!(S.base))

        exit(OVERFLOW);

    S.top = S.base;

    S.stacksize = Sinitsize;

}


Status Stackempty(Sqstack &S)

{

    if(S.top == S.base)

        return TRUE;

    else return ERROR;

}


void Push(Sqstack &S,int &e)

{

    if(S.top -S.base >= S.stacksize)

    {

        S.base = (Selemtype *)realloc(S.base,(S.stacksize + Sincrement) * sizeof(Selemtype));

        if(!(S.base))

            exit(OVERFLOW);

        S.top = S.base + S.stacksize;

        S.stacksize += Sincrement;

    }

    *(S.top)++ = e;

}


Status Pop(Sqstack &S,int &e)

{

    if(S.top == S.base)

        return ERROR;

    e = *(--S.top);

    return OK;

}


Status TopologicalOrder(Algraph &G, Sqstack &T)

{

    int count1=0;

    int count2=0;

    int i,k,N=0;

    int indegree[Maxvexnum];

    Sqstack S;

    Arcnode *p;

    Findindegree(G,indegree);

    Initstack(S);

    for(i = 0; i < G.vexnum; ++i)

    {

        if(indegree[i]==0)

        {

            Push(S,i); //入度为零者进栈

            count1++;

        }

        if(G.vertexs[i].firstarc==NULL)

             N++;

    }

    if(count1>1)

    {

        printf("图中有%d个源点,不能找出关键路径!!!\n",count1);

        return 0;

    }


    else  if(N>1)

    {

        printf("图中有%d个汇点,不能找出关键路径!!!\n",N);

        return 0;

    }//一个活动只有一个开始和一个结尾,故源点和汇点只可是一


    printf("\n");

    printf("拓扑序列:");

    Initstack(T);

    for(i = 0; i < G.vexnum; ++i)

        ve[i] = 0;

    while(!Stackempty(S))

    {


        Pop(S,i);

        printf("%s ",G.vertexs[i].data);

        Push(T,i);

        ++count2; //对输出顶点计数

        for(p = G.vertexs[i].firstarc; p; p = p->nextarc)

        {

            k = p->adjvex; //对i号顶点的每个邻接点的入度减一

            if(--indegree[k] == 0)

                Push(S,k);

            if(ve[i] + p->weight > ve[k])

                ve[k] = ve[i] + p->weight;

        }

    }

    printf("\n\n");

    if(count2 < G.vexnum)

    {

        printf("此有向网有回路\n");

        return 0;

    }

    else return 1;


}


Status CriticalPath(Algraph &G)

{

    int vl[Maxvexnum];

    Sqstack T;

    int i,j,k,ee,el,dut;

    Arcnode *p;

    if(!TopologicalOrder(G,T))

        return 0;//如果返回不是1,后面的不执行

    j= ve[0];

    for(i = 0; i < G.vexnum; i++)

        if(ve[i] > j)

            j = ve[i];//终点的活动对应的最早发生时间

    for(i = 0; i < G.vexnum; i++)

        vl[i] = j;//全部赋值成终点的活动对应的最早发生时间

    while(!Stackempty(T))

    {

        for(Pop(T,j),p = G.vertexs[j].firstarc; p ; p = p->nextarc)

        {

            k = p->adjvex;

            dut = p->weight;

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

                vl[j] = vl[k] - dut;

        }//栈T里面放的是逆拓扑序列,即放了对应的下标

    }

    printf("V  ve[i]  vl[i]\n");

    for(i = 0; i < G.vexnum; ++i)

    {

        printf("%s  %d  %5d",G.vertexs[i].data,ve[i],vl[i]);

        if(ve[i] == vl[i])

            printf("  关键路径经过的顶点");

        printf("\n");

    }

    printf("\n");

    printf("注释:V为事件,ve[i]为最早开始时间,vl[i]为最迟开始时间。\n");

    printf("\n");

    printf("j----k----权值----ee----el\n");

    for(j = 0; j < G.vexnum; ++j) //求ee,el和关键活动

        for(p = G.vertexs[j].firstarc; p ; p = p->nextarc)

        {

            k = p->adjvex;

            dut = p->weight;

            ee = ve[j];

            el = vl[k] - dut;

            printf("%s-->%s  %3d  %5d  %5d  ",G.vertexs[j].data,G.vertexs[k].data,dut,ee,el);

            if(ee == el)

                printf("关键活动");

            printf("\n");


        }//for

    printf("\n注释:ee为活动的最早开始时间,el为活动的最迟开始时间。");

    j--;

    printf("\n\n");

    printf("完成整项工程需要时间为:%d",ve[j]);

    printf("\n");

    return OK;

}

/*

www.quzhuanpan.comp

解释权来自去转盘网,转载请告知

*/

int main()

{

    system("color 5f");

    Algraph h;

    Creategraph(h);

    Display(h);

    CriticalPath(h);

    return 0;

}