如何求解關鍵路徑——怎樣計算工程所需的最短時間

AOE-網如下:

把圖中的AOE-網看作一個工程的話,則就需要解決下面兩個問題:

  • 估算完成整項工程至少需要多少時間
  • 判斷哪些活動是影響工程進度的關鍵

分析

     整個工程只有一個開始點和一個完成點,所以在正常的情況(無環)下,網中只有一個入度爲零的點,稱爲源點,也只有一個出度爲零的點,稱爲匯點。在整個AOE-網中,一條路徑各弧上的權值之和稱爲該路徑的帶權路徑長度。要估算整項工程完成的最短時間,就是要找一條從源點到匯點的帶權路徑最長的路徑,稱爲關鍵路徑。關鍵路徑上的活動叫做關鍵活動,這些活動是影響工程進度的關鍵,他們提前或拖延將使整個工程提前或拖延。

確定關鍵路徑

一,定義4個描述量

1,事件N的最早發生時間ve[N的下標]

進入事件N的每一活動都結束,N才能發生,所以ve[N的下標]是從源點到N的最長路徑長度

2,事件N的最遲發生時間vl[N的下標]

事件N的發生不得延遲於N的每一後繼事件的最遲發生時間。

爲了不拖延工期,N的最遲發生時間不得遲於其後繼事件M的最遲發生事件減去N到M的持續時間

eg:若N是B,M是E;則N的最遲發生時間不得遲於M的最遲發生時間減去MN之間的時間1.

3,活動的最早開始時間e[]

只有事件N發生了,活動x才能發生,所以,活動x的最早開始時間等於事件N的最早發生事件ve[N的下標]

eg:若N是B,x是代表BE這條弧,則只有事件B發生了,活動BE才能發生

4,活動的最晚開始時間l[]

活動x的開始事件需保證不延誤事件N的最遲發生時間。所以,活動x的最晚開始時間等於事件N的最遲發生時間vl[N的下標]減去活動x持續的時間

eg:若N是E,x是代表BE這條弧,則BE不能厭惡N的發生,所以最晚開始時間等於vl[N]-BE;

二,關鍵路徑求解過程

  1. 對圖中頂點進行排序,在排序過程中按照拓撲序列求出每個事件的最早發生時間ve[];
  2. 按照逆拓撲排序求出每個事件的最遲發生時間vl[];
  3. 求出每個活動XY的最早開始時間e[];
  4. 求出每個活動XV的最晚開始時間l[];
  5. 如果e[i]=l[i],即爲關鍵活動。由關鍵活動形成的由源點到匯點的每一條路徑就是關鍵路徑,關鍵路徑可能不止一條

三,關鍵路徑部分求解代碼

int ve[pointMax];      //最早發生時間
int vl[pointMax];      //最晚發生時間

void CritPath(ATgroup *A)
{
	int n = A->point;          //n爲頂點個數
	for (int i = 0; i < n; i++)        //將每個事件的最早事件爲0
		ve[i] = 0;

	//---按拓撲次序求每個事件的最早發生時間---//
	int k, j;
	for (int i = 0; i < n; i++)
	{
		k = topo[i];                 //取的拓撲排序中的頂點序號
		cout <<"K=F"<< k << "  "<<endl;
		VtNode *p = A->vertices[k].Out;     //指向K的第一個鄰接結點
		while (p != NULL)
		{
			j = p->peaceE;
			if (ve[j] < ve[k] + p->len)
			{
				ve[j] = ve[k] + p->len;
				cout << ve[j] << "  " << ve[k] << "   " << p->len << endl;
			}
			p = p->nextVtt;
		}
		cout << ve[j] << endl;
	}
	for (int i = 0; i < A->point; i++)
	{
		cout << ve[i] << "   ";
	}
	cout << endl;
	cout << endl;

	for (int i = 0; i < n; i++)       //初始化
	{
		vl[i] = ve[topo[n - 1]];
	}
	//---按逆拓撲排序求每個事件的最遲發生時間----//
	for (int i = n - 1; i >= 0; i--)
	{
		k = topo[i];                 //取的拓撲排序中的頂點序號
		VtNode *p = A->vertices[k].Out;     //指向K的第一個鄰接結點
		//cout << k << endl;
		while (p != NULL)
		{
			j = p->peaceE;
			if (vl[k] > vl[j] - p->len)
			{
				vl[k] = vl[j] - p->len;
				//cout << vl[k] << "  " << vl[j] << "   " << p->len << endl;
			}
			p = p->nextVtt;
		}
		//cout << vl[j] << endl;
	}

	for (int i = 0; i < A->point; i++)
	{
		cout << vl[i] << "   ";
	}
	cout << endl;
	cout << endl;

	//----判斷每一活動是否爲關鍵活動-----//
	int e, l;
	for (int i = 0; i < n; i++)
	{
		VtNode *p = A->vertices[i].Out;
		while (p != NULL)
		{
			j = p->peaceE;
			e = ve[i];
			l = vl[j] - p->len;
			if (e == l)
			{
				cout << A->vertices[i].data << "   " << A->vertices[j].data << endl;
			}
			p = p->nextVtt;
		}
	}
}

四,整段程序代碼

#include<iostream>
using namespace std;

#define pointMax 100

struct VtNode                 //權值信息
{
	VtNode *nextVt;           //入度鏈表下一個結點
	int peace;                //入度下一頂點的值

	VtNode *nextVtt;          //出度鏈表下一個結點
	int peaceE;               //出度下一頂點的值

	int len;
};
struct PoNode                  //頂點信息
{
	char data;
	VtNode *firstPo;          //入度
	VtNode *Out;              //出度
};

struct ATgroup
{
	PoNode vertices[pointMax];     //每一個verticse代表一個頂點
	int point, vert;               //point頂點數,vert弧數
};

struct Node
{
	int data;
	Node *next;
};

struct SqStack          //棧
{
	Node *base;          //棧底
	Node *top;           //棧頂
	int data;
};

void Push(SqStack &S, int i)       //入棧
{
	Node *m = new Node;
	m->data = i;
	m->next = S.top;             //入棧過程
	S.top = m;
}

int Pop(SqStack &S)              //出棧
{
	int n = S.top->data;
	S.top = S.top->next;         //出棧過程
	return n;
}


int ATlocate(ATgroup A, char x)             //找到位置
{
	for (int i = 0; i < A.point; i++)       //依次遍歷點的信息
	{
		if (A.vertices[i].data == x)        //找到x的位置
		{
			return i;
		}
	}
}

void show(ATgroup &A)                      //顯示當前所有點入度出度的頂點
{
	//cout << endl;
	for (int i = 0; i < A.point; i++)
	{
		//cout << i;
		if (A.vertices[i].firstPo != NULL)          //入度位置
		{
		//	cout << "    " << A.vertices[i].firstPo->peace << "   ";
		}
		//else
		//	cout << "    -1" << "    ";

		if (A.vertices[i].Out != NULL)             //出度位置
		{
		//	cout << A.vertices[i].Out->peaceE << endl;
		}
		//else
		//	cout << "    -1" << endl;
	}
}

void CreatAT(ATgroup &A)
{
	cout << "輸入鄰接矩陣頂點數:";
	cin >> A.point;
	cout << "輸入鄰接矩陣邊數:";
	cin >> A.vert;
	getchar();
	char q[100];
	cout << "輸入頂點信息:";
	gets_s(q);
	for (int i = 0; i < A.point; i++)
	{
		A.vertices[i].data = q[i];               //輸入頂點值
		A.vertices[i].firstPo = NULL;            //初始化頭結點爲空
		A.vertices[i].Out = NULL;
	}
	char v1, v2; int m, n; int len;
	for (int i = 0; i < A.vert; i++)            //輸入各邊,構造鄰接表
	{
		cout << "輸入第" << i << "條邊的依附的兩個頂點:";
		int Q;
		cin >> v1 >> v2 >> Q;
		m = ATlocate(A, v1);                  //確定位置
		n = ATlocate(A, v2);
		//第一個
		VtNode *p1 = new VtNode;
		VtNode *p2 = new VtNode;
		p1->peace = m;                             //入度
		p1->nextVt = A.vertices[n].firstPo;
		A.vertices[n].firstPo = p1;

		p2->peaceE = n;                            //出度
		p2->nextVtt = A.vertices[m].Out;
		p2->len = Q;
		A.vertices[m].Out = p2;
	}
	//show(A);
}

void FindIn(ATgroup *A, int *in)           //統計所有點的入度數並存入到in數組中
{
	int n = 0;
	for (int i = 0; i < A->point; i++)     //遍歷每一個點
	{
		VtNode *p = new VtNode;
		p = A->vertices[i].firstPo;
		while (p != NULL)                  //將入度鏈表進行遍歷
		{
			n++;
			p = p->nextVt;          //下一結點
		}
		in[i] = n;          //存入in數組
		n = 0;
	}
}

void SHOW(int *a, ATgroup *A)           //顯示當前所有頂點入度數量還有幾個
{
	for (int i = 0; i < A->point; i++)
	{
		//cout << a[i] << "  ";
	}
	//cout << endl;
}

int M[pointMax] = { 0 };
int topo[pointMax];           //拓撲遍歷存入

void TPsort(ATgroup *A, SqStack &S)           //拓撲排序過程
{
	int Indegree[pointMax];
	FindIn(A, Indegree);             //將入度賦值給數組

	for (int i = 0; i < A->point; i++)
	{
		if (Indegree[i] == 0)         //將所有入度等於0的入棧
		{
			//cout << "Push=" << i << endl;
			Push(S, i);
		}
	}

	int m = 0;                //統計入度的頂點數
	int n, k;

	while (S.base != S.top)       //判斷是否遍歷完
	{
		//cout << endl;
		n = Pop(S);         //棧頂出棧
		//cout << "Pop=" << n << endl;
		topo[m] = n;        //存入topo
		m++;
		VtNode* p = new VtNode;
		p = A->vertices[n].Out;             //出度鏈表的結點
		while (p != NULL)            //遍歷出度鏈表
		{
			k = p->peaceE;          //某結點的位置
			//cout << "出度下一結點k=" << k << endl;
			Indegree[k]--;          //將該結點頂點位置入度減一
			//SHOW(Indegree, A);       //顯示當前所有點的入度
			if (Indegree[k] == 0)      //當等於0時,入棧
			{
				//cout << "Push=" << k << endl;
				Push(S, k);
			}
			p = p->nextVtt;     //下一個
		}
	}
}



int ve[pointMax];      //最早發生時間
int vl[pointMax];      //最晚發生時間

void CritPath(ATgroup *A)
{
	int n = A->point;          //n爲頂點個數
	for (int i = 0; i < n; i++)        //將每個事件的最早事件爲0
		ve[i] = 0;

	//---按拓撲次序求每個事件的最早發生時間---//
	int k, j;
	for (int i = 0; i < n; i++)
	{
		k = topo[i];                 //取的拓撲排序中的頂點序號
		cout <<"K=F"<< k << "  "<<endl;
		VtNode *p = A->vertices[k].Out;     //指向K的第一個鄰接結點
		while (p != NULL)
		{
			j = p->peaceE;
			if (ve[j] < ve[k] + p->len)
			{
				ve[j] = ve[k] + p->len;
				cout << ve[j] << "  " << ve[k] << "   " << p->len << endl;
			}
			p = p->nextVtt;
		}
		cout << ve[j] << endl;
	}
	for (int i = 0; i < A->point; i++)
	{
		cout << ve[i] << "   ";
	}
	cout << endl;
	cout << endl;

	for (int i = 0; i < n; i++)       //初始化
	{
		vl[i] = ve[topo[n - 1]];
	}
	//---按逆拓撲排序求每個事件的最遲發生時間----//
	for (int i = n - 1; i >= 0; i--)
	{
		k = topo[i];                 //取的拓撲排序中的頂點序號
		VtNode *p = A->vertices[k].Out;     //指向K的第一個鄰接結點
		//cout << k << endl;
		while (p != NULL)
		{
			j = p->peaceE;
			if (vl[k] > vl[j] - p->len)
			{
				vl[k] = vl[j] - p->len;
				//cout << vl[k] << "  " << vl[j] << "   " << p->len << endl;
			}
			p = p->nextVtt;
		}
		//cout << vl[j] << endl;
	}

	for (int i = 0; i < A->point; i++)
	{
		cout << vl[i] << "   ";
	}
	cout << endl;
	cout << endl;

	//----判斷每一活動是否爲關鍵活動-----//
	int e, l;
	for (int i = 0; i < n; i++)
	{
		VtNode *p = A->vertices[i].Out;
		while (p != NULL)
		{
			j = p->peaceE;
			e = ve[i];
			l = vl[j] - p->len;
			if (e == l)
			{
				cout << A->vertices[i].data << "   " << A->vertices[j].data << endl;
			}
			p = p->nextVtt;
		}
	}
}

int main()
{
	ATgroup *A = new ATgroup;
	SqStack *S = new SqStack;
	S->top = S->base;
	S->data = pointMax;
	CreatAT(*A);
	TPsort(A, *S);
	CritPath(A);
	system("pause");
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章