图的关键路径

#include <iostream>
using namespace std;

//边表示活动的网AOE网,是基于假设:活动可以并行地进行,即从某顶点出发的几条边可以同时进行
const int MaxVertex=10;
const int MaxEdge=50;
struct Edge
{
int index; //邻接顶点的下标,表示第index个顶点
int weight;
Edge
*next;
};
struct item //表头结点结构
{
int data; //顶点数据
int id; //id表示入度数
Edge *adj; //邻接表指针
} ;
class AdjLinklistWGraph
{
private:
item Vertex[MaxVertex];
//相当于上面的int Vertex[MaxVertex],顶点数据的数组
int numVertex;int numEdge;
public:
AdjLinklistWGraph();
~AdjLinklistWGraph();
void CreatGraph();
void CreatLinklist(int vertex,int edge);
void printout();
void CriticalPath(); //关键路径
private:
void depth(int v,int visited[]);
void broad(int v,int visited[]);
};
AdjLinklistWGraph::AdjLinklistWGraph()
{
for(int i=0;i<MaxVertex;i++)
{
Vertex[i].data
=0; //顶点数据初始化为0
Vertex[i].id=0; //顶点的入度数初始化为0
Vertex[i].adj=NULL; //指针域置空
}
numVertex
=numEdge=0;
}
AdjLinklistWGraph::
~AdjLinklistWGraph()
{
for(int i=0;i<MaxVertex;i++)
{
Edge
*p=Vertex[i].adj,*q;
while(p!=NULL)
{
q
=p->next;delete p;p=q;
}
Vertex[i].adj
=NULL;
}
}
void AdjLinklistWGraph::CreatGraph()
{
int vertex, edge;
cout
<<"\n 请输入图的总顶点和总边数(vertex,edge=?) :";cin>>vertex>>edge;
CreatLinklist(vertex,edge);
}
void AdjLinklistWGraph::CreatLinklist(int vertex, int edge)
{
numVertex
=vertex;numEdge=edge;
int vi,vj,w,i;
cout
<<"\n 输入顶点的数据: ";
for(i=0;i<numVertex;i++)
{
cout
<<"\n"<<i+1<<": ";
cin
>>Vertex[i].data;
}
for(i=0;i<numEdge;i++)
{
cout
<<"\n 输入边的信息(顶点号vi,顶点号vj,边的权值w): ";
cin
>>vi>>vj>>w;
if(vi<1||vi>numVertex||vj<1||vj>numVertex){cout<<"\n v1或v2越界出错!\n";exit(-1);};

Vertex[vj
-1].id++;
//在第vi条链表上,插入边(vi,vj)结点
Edge *q=new Edge;
q
->index=vj-1;q->weight=w;q->next=NULL;
if(Vertex[vi-1].adj==NULL)Vertex[vi-1].adj=q; //首次插入
else{ //非第一次插入
Edge *curr=Vertex[vi-1].adj,*pre=NULL; //pre是curr的前驱
while(curr!=NULL&&curr->index<vj-1)
{
pre
=curr;curr=curr->next; //实现顶点的下标升序排列
}
if(pre==NULL) //即经过上面的第一次循环判断,curr->index<vj-1不成立,所以curr->index>vj-1,在第一个结点前插入
{
q
->next=Vertex[vi-1].adj;
Vertex[vi
-1].adj=q;
}
else{
q
->next=pre->next;pre->next=q; //在链表其它位置插入
}
}

/*
在第vj条链表上,插入边(vj,vi)结点, 这一段适合无向图
Edge *p=new Edge; //另外声明一个Edge变量
p->index=vi-1;p->weight=w;p->next=NULL;
if(Vertex[vj-1].adj==NULL)Vertex[vj-1].adj=p; //首次插入
else{ //非第一次插入
Edge *curr=Vertex[vj-1].adj,*pre=NULL; //pre是curr的前驱
while(curr!=NULL&&curr->index<vi-1)
{
pre=curr;curr=curr->next; //实现顶点的下标升序排列
}
if(pre==NULL) //即经过上面的第一次循环判断,curr->index<vj-1不成立,所以curr->index>vj-1,在第一个结点前插入
{
p->next=Vertex[vj-1].adj;
Vertex[vj-1].adj=p;
}
else{
p->next=pre->next;pre->next=p; //在链表其它位置插入
}
}
*/
}
}
void AdjLinklistWGraph::printout()
{
Edge
*curr;
for(int i=0;i<numVertex;i++)
{
cout
<<"\n 输出顶点编号信息,它的邻接点编号和相关边的权值: \n";
cout
<<"顶点编号"<<i+1<<" 顶点数据"<<Vertex[i].data<<endl;
curr
=Vertex[i].adj;
while(curr!=NULL)
{
cout
<<"邻接点编号 "<<curr->index+1<<"该边的权值 "<<curr->weight<<endl;
curr
=curr->next;

}
cout
<<endl;
}
}
void AdjLinklistWGraph::CriticalPath() //求关键路径需用到拓朴排序列
{
int front=0,rear=0;
int toposort[MaxVertex]; //toposort[]是存放入度为0的数组,事实上是保存拓朴排序列,以下的操作相当于队列
int ve[MaxVertex],vl[MaxVertex]; //分别存放各顶点(事件)的最早和最迟发生时间
int e[MaxEdge],l[MaxEdge]; //分别存放各条边(活动)的最早和最迟发生时间
int i,j,k,m;
Edge
*p;
for(i=0;i<numVertex;i++)ve[i]=0; //各顶点(事件)的最早发生时间置初值为0
for(i=0;i<numVertex;i++) //将入度为0的顶点入队
if(Vertex[i].id==0)toposort[rear++]=i;
m
=0; //计数器初始化
while(front!=rear)
{
j
=toposort[front];front++; //类似于下标为j顶点出队
m++;
p
=Vertex[j].adj;
while(p!=NULL)
{
k
=p->index;
Vertex[k].id
--;
if(ve[j]+p->weight>ve[k])ve[k]=ve[j]+p->weight; //最早发生时间是从开始顶点到该顶点的最长路径长度
if(Vertex[k].id==0)toposort[rear++]=k;
p
=p->next;
}
}
if(m<numVertex){
cout
<<"图中存在有向回路\n";return ;
}

//求各事件的最迟发生时间
for(i=0;i<numVertex;i++)vl[i]=ve[numVertex-1];
for(i=numVertex-2;i>=0;i--) //按拓朴序列的逆序取顶点
{
j
=toposort[i];
p
=Vertex[j].adj;
while(p!=NULL)
{
k
=p->index;
if((vl[k]-p->weight)<vl[j])vl[j]=vl[k]-p->weight;//最迟发生时间是整个路径长度减去从结束顶点到该顶点的最长路径长度
p=p->next;
}
}

//求各条边(活动)的最早和最迟发生时间
m=0; //边计数器
for(i=0;i<numVertex;i++) //扫描顶点
{
p
=Vertex[i].adj;
while(p!=NULL)
{
k
=p->index;
e[m]
=ve[i]; //最早发生时间就是该条边的起始顶点的最早发生时间
l[m]=vl[k]-p->weight; //最迟发生时间就是该条边的结束顶点的最晚发生时间减去该条边的活动时间,即权值
cout<<""<<Vertex[i].data<<""<<Vertex[k].data<<" 最早发生时间 "<<e[m]<<" 最迟发生时间 "
<<l[m]<<" 二者的差: "<<l[m]-e[m]<<endl;
if(l[m]==e[m])cout<<"这是关键活动\n\n";
p
=p->next;
m
++;
}
}
}


void main()
{
AdjLinklistWGraph ALWgraph;
ALWgraph.CreatGraph();
ALWgraph.CriticalPath();


}
/*

9 11
1
2
3
4
5
6
7
8
9
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 7
5 8 5
6 8 4
7 9 2
8 9 4


*/

  

posted on 2011-08-24 21:12  sysu_mjc  阅读(384)  评论(0编辑  收藏  举报

导航