C++ AOE网络
一、思路(你可以用拓?fù)渑判騺碜?#xff0c;但我這里沒用拓?fù)渑判?
??? (1)求事件Vi的最早可能開始時(shí)間是從源點(diǎn)V0到頂點(diǎn)Vi的最長(zhǎng)路徑長(zhǎng)度。
???????????? 如V0=0, V1=6,V2=4,V3=5;V4事件要等V1和V2事件完成后才可以進(jìn)行,所以要取事件用的最長(zhǎng)的時(shí)間,即V4=6+1=7,同樣道理得出其他時(shí)間。
??? (2)事件Vi的最遲允許開始時(shí)間Vl[i]是在保證匯點(diǎn)Vn-1在Ve[n-1]時(shí)刻完成的前提下,事件Vi的允許的最遲開始時(shí)間。它等于Ve[n-1]減去從Vi到Vn-1的最長(zhǎng)路徑。
???????? 如:事件V2=Ve[n-1]-(a7+a10)-a5 = 18-11-1=6
??? (3)活動(dòng)ak的最早可能開始時(shí)間Ae[k]=Ve[i](k=1,2,…)(i=0,1,…)
??? (4)活動(dòng)ak的最遲允許開始時(shí)間Al[k]=Vl[j]-<i,j>
??? (5)用Al[k]-Ae[k]表示活動(dòng)ak的最早可能開始時(shí)間和最遲允許開始時(shí)間的時(shí)間余量,也叫做松弛時(shí)間。Al[k]==Ae[k]表示活動(dòng)ak是沒有時(shí)間余量的關(guān)鍵活動(dòng)。
| 事件 | V0 | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 |
| Ve[i] | 0 | 6 | 4 | 5 | 7 | 7 | 16 | 14 | 18 |
| Vl[i] | 0 | 6 | 6 | Ve[8]-a11-a9-a6=8 | 7 | 10 | 16 | 14 | 18 |
?
| 邊 | <0, 1> | <0, 2> | <0, 3> | <1, 4> | <2, 4> | <3, 5> | <4, 6> | <4, 7> | <5, 7> | <6, 8> | <7, 8> |
| 活動(dòng) | a1 | a2 | a3 | a4 | a5 | a6 | a7 | a8 | a9 | a10 | a11 |
| Ae | Ve[i]=Ve[0]=0 | Ve[i]=Ve[0]=0 | Ve[i]=Ve[0]=0 | Ve[i]=Ve[1]=6 | Ve[2]=0 4 | 5 | 7 | 7 | 7 | 16 | 14 |
| Al | Vl[1]-6=6-6=0 | Vl[2]-<0,2>=6-4=2 | Vl[3]-<0,3>=8-5=3 | 6 | 6 | 8 | 7 | 7 | 10 | 16 | 14 |
| Al-Ae | 0 | 2 | 3 | 0 | 2 | 3 | 0 | 0 | 3 | 0 | 0 |
| 關(guān)鍵活動(dòng) | 是 | ? | ? | 是 | ? | ? | 是 | 是 | ? | ? | 是 |
?
二、實(shí)現(xiàn)程序:
1.Graph.h:有向圖的鏈表表示
#ifndef Graph_h #define Graph_h#include <iostream> using namespace std;const int DefaultVertices = 30;template <class T, class E> struct Edge { // 邊結(jié)點(diǎn)的定義int dest; // 邊的另一頂點(diǎn)位置E cost; // 表上的權(quán)值Edge<T, E> *link; // 下一條邊鏈指針 };template <class T, class E> struct Vertex { // 頂點(diǎn)的定義T data; // 頂點(diǎn)的名字Edge<T, E> *adj; // 邊鏈表的頭指針 };template <class T, class E> class Graphlnk { public:const E maxValue = 100000; // 代表無窮大的值(=∞)Graphlnk(int sz=DefaultVertices); // 構(gòu)造函數(shù)~Graphlnk(); // 析構(gòu)函數(shù)void inputGraph(); // 建立鄰接表表示的圖void outputGraph(); // 輸出圖中的所有頂點(diǎn)和邊信息T getValue(int i); // 取位置為i的頂點(diǎn)中的值E getWeight(int v1, int v2); // 返回邊(v1, v2)上的權(quán)值bool insertVertex(const T& vertex); // 插入頂點(diǎn)bool insertEdge(int v1, int v2, E weight); // 插入邊bool removeVertex(int v); // 刪除頂點(diǎn)bool removeEdge(int v1, int v2); // 刪除邊int getFirstNeighbor(int v); // 取頂點(diǎn)v的第一個(gè)鄰接頂點(diǎn)int getNextNeighbor(int v,int w); // 取頂點(diǎn)v的鄰接頂點(diǎn)w的下一鄰接頂點(diǎn)int getVertexPos(const T vertex); // 給出頂點(diǎn)vertex在圖中的位置int numberOfVertices(); // 當(dāng)前頂點(diǎn)數(shù) private:int maxVertices; // 圖中最大的頂點(diǎn)數(shù)int numEdges; // 當(dāng)前邊數(shù)int numVertices; // 當(dāng)前頂點(diǎn)數(shù)Vertex<T, E> * nodeTable; // 頂點(diǎn)表(各邊鏈表的頭結(jié)點(diǎn)) };// 構(gòu)造函數(shù):建立一個(gè)空的鄰接表 template <class T, class E> Graphlnk<T, E>::Graphlnk(int sz) {maxVertices = sz;numVertices = 0;numEdges = 0;nodeTable = new Vertex<T, E>[maxVertices]; // 創(chuàng)建頂點(diǎn)表數(shù)組if(nodeTable == NULL) {cerr << "存儲(chǔ)空間分配錯(cuò)誤!" << endl;exit(1);}for(int i = 0; i < maxVertices; i++)nodeTable[i].adj = NULL; }// 析構(gòu)函數(shù) template <class T, class E> Graphlnk<T, E>::~Graphlnk() {// 刪除各邊鏈表中的結(jié)點(diǎn)for(int i = 0; i < numVertices; i++) {Edge<T, E> *p = nodeTable[i].adj; // 找到其對(duì)應(yīng)鏈表的首結(jié)點(diǎn)while(p != NULL) { // 不斷地刪除第一個(gè)結(jié)點(diǎn)nodeTable[i].adj = p->link;delete p;p = nodeTable[i].adj;}}delete []nodeTable; // 刪除頂點(diǎn)表數(shù)組 }// 建立鄰接表表示的圖 template <class T, class E> void Graphlnk<T, E>::inputGraph() {int n, m; // 存儲(chǔ)頂點(diǎn)樹和邊數(shù)int i, j, k;T e1, e2; // 頂點(diǎn)E weight; // 邊的權(quán)值cout << "請(qǐng)輸入頂點(diǎn)數(shù)和邊數(shù):" << endl;cin >> n >> m;cout << "請(qǐng)輸入各頂點(diǎn):" << endl;for(i = 0; i < n; i++) {cin >> e1;insertVertex(e1); // 插入頂點(diǎn)}cout << "請(qǐng)輸入圖的各邊的信息:" << endl;i = 0;while(i < m) {cin >> e1 >> e2 >> weight;j = getVertexPos(e1);k = getVertexPos(e2);if(j == -1 || k == -1)cout << "邊兩端點(diǎn)信息有誤,請(qǐng)重新輸入!" << endl;else {insertEdge(j, k, weight); // 插入邊i++;}} // while }// 輸出有向圖中的所有頂點(diǎn)和邊信息 template <class T, class E> void Graphlnk<T, E>::outputGraph() {int n, m, i;T e1, e2; // 頂點(diǎn)E weight; // 權(quán)值Edge<T, E> *p;n = numVertices;m = numEdges;cout << "圖中的頂點(diǎn)數(shù)為" << n << ",邊數(shù)為" << m << endl;for(i = 0; i < n; i++) {p = nodeTable[i].adj;while(p != NULL) {e1 = getValue(i); // 有向邊<i, p->dest>e2 = getValue(p->dest);weight = p->cost;cout << "<" << e1 << ", " << e2 << ", " << weight << ">" << endl;p = p->link; // 指向下一個(gè)鄰接頂點(diǎn)}} }// 取位置為i的頂點(diǎn)中的值 template <class T, class E> T Graphlnk<T, E>::getValue(int i) {if(i >= 0 && i < numVertices)return nodeTable[i].data;return NULL; }// 返回邊(v1, v2)上的權(quán)值 template <class T, class E> E Graphlnk<T, E>::getWeight(int v1, int v2) {if(v1 != -1 && v2 != -1) {Edge<T , E> *p = nodeTable[v1].adj; // v1的第一條關(guān)聯(lián)的邊while(p != NULL && p->dest != v2) { // 尋找鄰接頂點(diǎn)v2p = p->link;}if(p != NULL)return p->cost;}return maxValue; // 邊(v1, v2)不存在,就存放無窮大的值 }// 插入頂點(diǎn) template <class T, class E> bool Graphlnk<T, E>::insertVertex(const T& vertex) {if(numVertices == maxVertices) // 頂點(diǎn)表滿,不能插入return false;nodeTable[numVertices].data = vertex; // 插入在表的最后numVertices++;return true; }// 插入邊 template <class T, class E> bool Graphlnk<T, E>::insertEdge(int v1, int v2, E weight) {if(v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices) {Edge<T, E> *p = nodeTable[v1].adj; // v1對(duì)應(yīng)的邊鏈表頭指針while(p != NULL && p->dest != v2) // 尋找鄰接頂點(diǎn)v2p = p->link;if(p != NULL) // 已存在該邊,不插入return false;p = new Edge<T, E>; // 創(chuàng)建新結(jié)點(diǎn)p->dest = v2;p->cost = weight;p->link = nodeTable[v1].adj; // 鏈入v1邊鏈表nodeTable[v1].adj = p;numEdges++;return true;}return false; }// 有向圖刪除頂點(diǎn)較麻煩 template <class T, class E> bool Graphlnk<T, E>::removeVertex(int v) {if(numVertices == 1 || v < 0 || v > numVertices)return false; // 表空或頂點(diǎn)號(hào)超出范圍Edge<T, E> *p, *s;// 1.清除頂點(diǎn)v的邊鏈表結(jié)點(diǎn)w 邊<v,w>while(nodeTable[v].adj != NULL) {p = nodeTable[v].adj;nodeTable[v].adj = p->link;delete p;numEdges--; // 與頂點(diǎn)v相關(guān)聯(lián)的邊數(shù)減1} // while結(jié)束// 2.清除<w, v>,與v有關(guān)的邊f(xié)or(int i = 0; i < numVertices; i++) {if(i != v) { // 不是當(dāng)前頂點(diǎn)vs = NULL;p = nodeTable[i].adj;while(p != NULL && p->dest != v) {// 在頂點(diǎn)i的鏈表中找v的頂點(diǎn)s = p;p = p->link; // 往后找}if(p != NULL) { // 找到了v的結(jié)點(diǎn)if(s == NULL) { // 說明p是nodeTable[i].adjnodeTable[i].adj = p->link;} else {s->link = p->link; // 保存p的下一個(gè)頂點(diǎn)信息}delete p; // 刪除結(jié)點(diǎn)pnumEdges--; // 與頂點(diǎn)v相關(guān)聯(lián)的邊數(shù)減1}}}numVertices--; // 圖的頂點(diǎn)個(gè)數(shù)減1nodeTable[v].data = nodeTable[numVertices].data; // 填補(bǔ),此時(shí)numVertices,比原來numVertices小1,所以,這里不需要numVertices-1nodeTable[v].adj = nodeTable[numVertices].adj;// 3.要將填補(bǔ)的頂點(diǎn)對(duì)應(yīng)的位置改寫for(int i = 0; i < numVertices; i++) {p = nodeTable[i].adj;while(p != NULL && p->dest != numVertices) // 在頂點(diǎn)i的鏈表中找numVertices的頂點(diǎn)p = p->link; // 往后找if(p != NULL) // 找到了numVertices的結(jié)點(diǎn)p->dest = v; // 將鄰接頂點(diǎn)numVertices改成v}return true; }// 刪除邊 template <class T, class E> bool Graphlnk<T, E>::removeEdge(int v1, int v2) {if(v1 != -1 && v2 != -1) {Edge<T, E> * p = nodeTable[v1].adj, *q = NULL;while(p != NULL && p->dest != v2) { // v1對(duì)應(yīng)邊鏈表中找被刪除邊q = p;p = p->link;}if(p != NULL) { // 找到被刪除邊結(jié)點(diǎn)if(q == NULL) // 刪除的結(jié)點(diǎn)是邊鏈表的首結(jié)點(diǎn)nodeTable[v1].adj = p->link;elseq->link = p->link; // 不是,重新鏈接delete p;return true;}}return false; // 沒有找到結(jié)點(diǎn) }// 取頂點(diǎn)v的第一個(gè)鄰接頂點(diǎn) template <class T, class E> int Graphlnk<T, E>::getFirstNeighbor(int v) {if(v != -1) {Edge<T, E> *p = nodeTable[v].adj; // 對(duì)應(yīng)鏈表第一個(gè)邊結(jié)點(diǎn)if(p != NULL) // 存在,返回第一個(gè)鄰接頂點(diǎn)return p->dest;}return -1; // 第一個(gè)鄰接頂點(diǎn)不存在 }// 取頂點(diǎn)v的鄰接頂點(diǎn)w的下一鄰接頂點(diǎn) template <class T, class E> int Graphlnk<T, E>::getNextNeighbor(int v,int w) {if(v != -1) {Edge<T, E> *p = nodeTable[v].adj; // 對(duì)應(yīng)鏈表第一個(gè)邊結(jié)點(diǎn)while(p != NULL && p->dest != w) // 尋找鄰接頂點(diǎn)wp = p->link;if(p != NULL && p->link != NULL)return p->link->dest; // 返回下一個(gè)鄰接頂點(diǎn)}return -1; // 下一個(gè)鄰接頂點(diǎn)不存在 }// 給出頂點(diǎn)vertex在圖中的位置 template <class T, class E> int Graphlnk<T, E>::getVertexPos(const T vertex) {for(int i = 0; i < numVertices; i++)if(nodeTable[i].data == vertex)return i;return -1; }// 當(dāng)前頂點(diǎn)數(shù) template <class T, class E> int Graphlnk<T, E>::numberOfVertices() {return numVertices; }#endif /* Graph_h */2.AOE.h
#ifndef AOE_h #define AOE_h #include "Graph.h"// 計(jì)算關(guān)鍵路徑的算法 template <class T, class E> void CirticalPath(Graphlnk<T, E>& G) {int i, j, k, n;E Ae, Al, w;n = G.numberOfVertices(); // 圖的頂點(diǎn)數(shù)E *Ve = new E[n];E *Vl = new E[n];for(i = 0; i < n; i++) // 初始化最早開始事件時(shí)間Ve[i] = 0;// 正向計(jì)算Ve[i],時(shí)間Vi的最早可能開始時(shí)間:從源點(diǎn)V0到頂點(diǎn)Vi的最長(zhǎng)路徑長(zhǎng)度for(i = 0; i < n; i++) {j = G.getFirstNeighbor(i); // 鄰接頂點(diǎn)while(j != -1) { // 存在鄰接頂點(diǎn)w = G.getWeight(i, j);if(Ve[i] + w > Ve[j]) // 要等前面時(shí)間最長(zhǎng)的活動(dòng)完了,才可以進(jìn)行j事件Ve[j] = Ve[i] + w;j = G.getNextNeighbor(i, j); // 下一個(gè)鄰接頂點(diǎn)}}// 逆向計(jì)算Vl[]Vl[n-1] = Ve[n-1]; // 最終完成事件時(shí)間for(j = n-2; j > 0; j--) {k = G.getFirstNeighbor(j);Vl[j] = Ve[n-1]; // 假設(shè)最大為Ve[n-1]while(k != -1) { // 存在鄰接邊w = G.getWeight(j, k);if(Vl[k] - w < Vl[j])Vl[j] = Vl[k] - w; // 事件最遲允許開始時(shí)間k = G.getNextNeighbor(j, k);}}for(i = 0; i < n; i++) { // 求各活動(dòng)的Ae, A1j = G.getFirstNeighbor(i);while(j != -1) {Ae = Ve[i]; // 活動(dòng)ak最早可能開始時(shí)間Al = Vl[j] - G.getWeight(i, j); // 時(shí)間j最遲可能開始時(shí)間-活動(dòng)ak需要的時(shí)間if(Al == Ae)cout << "<" << G.getValue(i) << "," << G.getValue(j) << ">" << "是關(guān)鍵活動(dòng)" << endl;j = G.getNextNeighbor(i, j);}}delete []Ve; // 釋放動(dòng)態(tài)分配的空間delete []Vl; }#endif /* AOE_h */3.main.cpp
#include "AOE.h"int main(int argc, const char * argv[]) {Graphlnk<char, int> G; // 聲明圖對(duì)象// 創(chuàng)建圖G.inputGraph();cout << "圖的信息如下:" << endl;G.outputGraph();// 調(diào)用計(jì)算關(guān)鍵路徑的函數(shù)cout << "關(guān)鍵路徑如下:" << endl;CirticalPath(G);return 0; }測(cè)試數(shù)據(jù):
9 11
0 1 2 3 4 5 6 7 8
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
?
測(cè)試結(jié)果:
?
總結(jié)
- 上一篇: Python图书商城(可运行代码)有说明
- 下一篇: s3c2440移植MQTT