#include <iostream>
#include <iomanip>
#include <stack>
using namespace std;
#define MAX 100
typedef char VertexType;
typedef struct ArcNode {
int adjvex; //鄰接點域,存儲該弧指向頂點的下標 (終點)
struct ArcNode *next; //指向下一條弧的指針
int weight; //權重
}ArcNode; //邊結構
typedef struct VertexNode {
VertexType data; //數據域
ArcNode *firstArc; //指向第一條依附該頂點的弧的指針
}VertexNode,AdjVerList[MAX];
typedef struct {
AdjVerList vertices; //頂點集
int vexnum,arcnum; //圖的頂點數和弧數
}ALGraph; //圖結構
int ve[MAX]; //各事件的最早發生時間
void CreateALGraph(ALGraph *G);
void Display(ALGraph *G);
int CriticalPath(ALGraph *G);
/*
求關鍵路徑的基本步驟:
1.對圖中頂點進行拓撲排序,在排序過程中按拓撲系列求出每個事件的最早發生事件ve(i)
2.按逆拓撲序列求出每個事件的最晚發生時間vl(i)
3.求出每個活動i的最早開始時間 e(i)和最晚發生時間l(i)
4.找到e(i)=l(i)的活動,即爲關鍵路徑
*/
int main()
{
ALGraph G;
CreateALGraph(&G);
CriticalPath(&G);
return 0;
}
//求頂點位置函數
int LocateVex(ALGraph *G,VertexType v)
{
int i;
for(i=0;i<G->vexnum;i++)
{
if(G->vertices[i].data == v)
return i;
}
return -1;
}
//有向無環圖
void CreateALGraph(ALGraph *G)
{
VertexType v1,v2;
int w;
ArcNode *Arc;
cout<<"請輸入頂點數和邊數:";
cin>>G->vexnum>>G->arcnum;
cout<<"請輸入各頂點的數據:";
for(int i=0;i<G->vexnum;i++){
cin>>G->vertices[i].data;
G->vertices[i].firstArc = NULL; //頂點的邊表設爲空
}
cout<<"請依次輸入"<<G->arcnum<<"組邊對應的兩個頂點以及權值,以空格分割:"<<endl;
for(int k=0;k<G->arcnum;k++) {
cin>>v1>>v2>>w;
int i = LocateVex(G,v1);
int j = LocateVex(G,v2);
Arc = new ArcNode; //新建邊
Arc->adjvex = j;
Arc->weight = w;
Arc->next = G->vertices[i].firstArc;
G->vertices[i].firstArc = Arc;
}
}
//求各頂點的入度(遍歷整個鄰接表)
void FindIndegree(ALGraph *G,int indegree[MAX])
{
int i;
ArcNode *p;
//初始化每個頂點的入度爲0
for(i=0;i<G->vexnum;i++)
indegree[i] = 0;
for(i=0;i<G->vexnum;i++)
{
p = G->vertices[i].firstArc;
while(p)
{
indegree[p->adjvex]++; //將每一個臨接到的點(終點)自增
p = p->next;
}
//cout<<i<<"元素的入度爲:"<<indegree[i]<<endl;
}
}
//拓撲排序
int TopoSort(ALGraph *G,stack<int> &T) //T爲返回逆拓撲序列的棧
{
stack<int> s; //設置輔助棧(正拓撲序列棧)
ArcNode *p;
int i,k;
int indegree[MAX]; //各頂點的入度數組
FindIndegree(G,indegree);
for(i=0;i<G->vexnum;i++)
{
//將入度爲0的頂點入棧
if(indegree[i]==0)
s.push(i);
}
for(i=0;i<G->vexnum;i++)
ve[i] = 0; //初始化最早發生時間
int count = 0;
while(!s.empty())
{
i = s.top();
s.pop(); //將棧頂從S棧出棧
T.push(i); //將i節點進入T棧,形成逆拓撲序列
count++; //統計已輸出的頂點數
p = G->vertices[i].firstArc;
while(p!=NULL)
{
k = p->adjvex;
indegree[k]--; //i號頂點已出棧,所以將i號頂點的每個鄰接點的入度自減
if(indegree[k]==0)
s.push(k); //如果入度減爲0,則入棧
if(ve[i]+p->weight>ve[k])
ve[k] = ve[i]+p->weight; //按拓撲順序更新事件的最早發生事件
p = p->next;
}
}
if(count<G->vexnum)
return -1; //存在迴路
else
return 0;
}
//求關鍵路徑(AOE網,邊表示活動的網)
int CriticalPath(ALGraph *G)
{
int i,j,k;
int dut,ei,li;
int vl[MAX]; //每個事件的最晚發生事件
ArcNode *p;
stack<int> T;
if(TopoSort(G,T)) //求事件的最早發生時間和逆拓撲序列
return -1;
for(i=0;i<G->vexnum;i++)
vl[i] = ve[G->vexnum-1]; //將各事件的最遲發生事件初始化爲匯點的最早發生時間
while(!T.empty()) //按逆拓撲序列求各事件的最晚發生時間
{
j = T.top();
T.pop();
p = G->vertices[j].firstArc;
while(p!=NULL) //遍歷整個棧
{
k = p->adjvex;
dut = p->weight;
if(vl[k]-dut<vl[j])
vl[j] = vl[k]-dut;
p = p->next;
}
}
cout<<"關鍵活動的相關信息如下:"<<endl;
cout<<"活動"<<setw(16)<<"最早發生時間"<<setw(16)<<"最晚發生時間"<<setw(10)<<"持續時間"<<endl;
for(j =0;j<G->vexnum;j++) //掃描每一條弧,求出e(i),l(i),找出關鍵路徑
{
p = G->vertices[j].firstArc;
while(p)
{
k = p->adjvex;
dut = p->weight;
ei = ve[j]; //活動的最早發生時間
li = vl[k]-dut; //活動的最晚發生時間
if(ei==li) //輸出關鍵活動的相關信息(ei,li,dut)
{
cout<<"("<<G->vertices[j].data<<","<<G->vertices[k].data<<")"<<setw(10)<<ei
<<setw(14)<<li<<setw(14)<<dut<<endl;
}
p = p->next;
}
}
return 0;
}
/*
a b c d e f g h i
a b 6
a c 4
a d 5
b e 1
c e 1
d f 2
e g 9
b h 7
f h 4
g i 2
h i 4
*/
關鍵路徑
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.