一共四步
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;
//新增边的权值与id
void createGraph(gLink g)
{
int n,v,data;
printf("请输入顶点数与边数");
scanf("%d %d",&n,&v);
g->n = n;
g->v = v;
int i;
for(i=0;iadj[i].data = data;
g->adj[i].first = NULL;
}
printf("请输入边信息");
int v1,v2,da;
for(i=0;itoVertex = 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;in;i++)
{
a[i]=0;
}
for(i=0;in;i++)
{
sLink s = g->adj[i].first;
while(s)
{
a[s->toVertex]++;
s = s->next;
}
}
}
//全局变量
int vers[15];//栈,装入拓扑排序,用于逆拓扑排序
int top = -1;//栈指针
//顶点-->事件发生:最早ve,最晚vl
//边-->活动:最早e,最晚l
int ve[15]={0},vl[15]={0},e[15]={0},l[15]={0};
//拓扑排序求ve
void tuopu(gLink g)
{
int queue[10];
int front=0, rear=0;
int a[g->n];
inDegree(g,a);
int i;
for(i=0;in;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->datatoVertex]-s->data;//为每一个前驱顶点赋值vl
s = s->next;
}
}
//求e和l
//从顶点遍历,为每一个边确定e和l
for(i=0;in;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;iv;i++)
{
if(l[i]==e[i])
{
printf("a%-5d",i);
//遍历图,找到id为这个的边
for(j=0;jn;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;
}