#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;
}