1 / 128

# 图 图的存储表示 图的遍历 无向图的连通分量和生成树 最短路径 拓扑排序 - PowerPoint PPT Presentation

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about ' 图 图的存储表示 图的遍历 无向图的连通分量和生成树 最短路径 拓扑排序' - majed

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

• 图的存储表示
• 图的遍历
• 无向图的连通分量和生成树
• 最短路径
• 拓扑排序

v1

v3

v2

v1

v5

v3

v4

v4

v2

G=<V, E>

V={v1,v2,······,vn} 顶点集

E={ (vi, vj) | vi,vj∈V, vi≠vj} 边集 无向图

E={<vi, vj>|vi ,vj∈V}有向边集 有向图

TD(vi):一个顶点的度,以vi为端点的边的数目。

OD(vi): 出度, 以vi为起点的边的数目。

ID(vi): 入度，以vi为终点的边的数目。

TD(vi)= OD(vi)+ ID(vi)

OD=ID, TD=2|E|， |E| =1/2*TD

TD OD ID 为整个图的总度,出度,入度数。

vivj连通 有路径 vi······vj，

v2

v2

v1

v1

v4

v4

v3

v3

v5

v5

G=(V, E), G’=(V’, E’)

n个顶点尽可能少边的连通图有n-1条边。

1.邻接矩阵

A[i,j]=1 (vi,vj)∈E

=0 o.w.

0 1 1 0 0

1 0 0 1 1

1 0 0 0 1

0 1 0 0 0

0 1 1 0 0

v1

v2

v5

v3

v4

0 1 1 0 0

1 0 0 1 1

1 0 0 0 1

0 1 0 0 0

0 1 1 0 0

TD(vi)=ΣA[i,j] i行数字的和等于vi的度

v1

v2

v5

v3

v4

n

j=1

n

n

|E|=1/2 ΣΣA[i,j] 全部数字的和等于边数*2

i=1

j=1

A[i,j]=1 <vi,vj>∈E

=0 o.w.

0 1 1 0

0 0 0 1

1 0 0 0

1 0 0 0

v3

v1

v4

v2

n

OD(vi)=ΣA[i,j] i行数字的和等于vi的出度

j=1

n

n

|E|= ΣΣA[i,j] 全部数字的和等于边数

i=1

j=1

A[i,j]=wi (vi,vj)∈E 权为wi

=∞ o.w.

∞ 5 ∞ 7 ∞ ∞

∞ ∞ 4 ∞ ∞ ∞

8 ∞ ∞ ∞ ∞ 9

∞ ∞ 5 ∞ ∞ 6

∞ ∞ ∞ 5 ∞ ∞

3 ∞ ∞ ∞ 1 ∞

5

v2

v1

4

8

v3

7

3

9

v6

6

1

5

v5

v4

5

#ifndef GRAPH_CLASS#define GRAPH_CLASS#include <iostream.h>#include <fstream.h>#include "stack.h"#include "pqueue.h"#include "queue.h"#include "seqlist2.h"const intMaxGraphSize= 25;

template <class T>class VertexIterator;template <class T> class Graph{ SeqList<T> vertexList; int edge [MaxGraphSize][MaxGraphSize]; int graphsize; int FindVertex(SeqList<T> &L, const T& vertex); int GetVertexPos(const T& vertex);

public: Graph(void); int GraphEmpty(void) const; int GraphFull(void) const; int NumberOfVertices(void) const;int GetWeight(const T& vertex1, const T& vertex2); SeqList<T>& GetNeighbors(const T& vertex); int GetFirstNeighbor(const int v); int GetNextNeighbor(const int v1, const int v2);

// graph modification methods void InsertVertex(const T& vertex);void InsertEdge(const T& vertex1, const T& vertex2, int weight); void DeleteVertex(const T& vertex);void DeleteEdge(const T& vertex1, const T& vertex2);

// utility methods void ReadGraph(char *filename);SeqList<T>& DFS( ); SeqList<T>& DFS(const int v, int *visited); SeqList<T>& DepthFirstSearch(const T& beginVertex); SeqList<T>& BreadthFirstSearch(const T& beginVertex);int MinimumPath(const T& sVertex, const T& eVertex); // iterator used to scan the vertices friend class VertexIterator<T>;};

2. 邻接表

A

B

E

C

D

Const int MaxGraphSize=25;

template <class T>

struct Edge //边的类 第一个顶点是隐式的

int weight;

Edge<T> *next; //指向下一条边的指针

Edge(int v,int w):ajvex(v),weight(w),next(0){ }

~Edge( ){delete next;}

};

template<class T>

struct VNode

{ Tvertex;

Edge<T> *firstedge;

}

template<class T>

class ALGraph

{ VNode vertexArry[MaxGraphSize] ;

int vexNum, edgeNum;

int FindVertex(SeqList<T> &L, const T& vertex); int GetVertexPos(const T& vertex);

public: ALGraph(void); int GraphEmpty(void) const; int GraphFull(void) const; int NumberOfVertices(void) const;int GetWeight(const T& vertex1, const T& vertex2); SeqList<T>& GetNeighbors(const T& vertex); int GetFirstNeighbor(const int v); int GetNextNeighbor(const int v1, const int v2);

// graph modification methods void InsertVertex(const T& vertex);void InsertEdge(const T& vertex1, const T& vertex2, int weight); void DeleteVertex(const T& vertex);void DeleteEdge(const T& vertex1, const T& vertex2);

// utility methods void ReadGraph(char *filename);SeqList<T>& DFS( ); SeqList<T>& DFS(const int v, int *visited); SeqList<T>& DepthFirstSearch(const T& beginVertex); SeqList<T>& BreadthFirstSearch(const T& beginVertex);int MinimumPath(const T& sVertex, const T& eVertex);};

//邻接矩阵表示的图的实现// constructor initialize entries in the adjacency matrix// to 0 and sets the graphsize to 0template <class T>Graph<T>::Graph(void){ for (int i = 0; i < MaxGraphSize; i++) for (int j = 0; j < MaxGraphSize; j++)edge[i][j] = 0;graphsize = 0;}

0 1 1 0 0

1 0 0 1 1

1 0 0 0 1

0 1 0 0 0

0 1 1 0 0

A

B

E

C

D

5

A B C D E

5

A B 1

A C 1

B D 1

B E 1

C E 1

Graph<char>G;

template <class T >void Graph< T >::ReadGraph(char *filename){ int i, nvertices, nedges;T S1, S2; int weight; ifstream f;f.open(filename, ios::in | ios::nocreate); if(!f){ cerr << "Cannot open " << filename << endl; exit(1); }f >> nvertices; for (i = 0; i < nvertices; i++) { f >> S1; InsertVertex(S1); }f >> nedges; for (i = 0; i < nedges; i++) { f >> S1; f >> S2; f >> weight; InsertEdge(S1,S2, weight); }f.close( ); }

template <class T>int Graph<T>::NumberOfVertices(void) const{ return graphsize;}

template <class T>int Graph<T>::GraphEmpty(void) const{ return graphsize == 0;}

template <class T>int Graph<T>::GetVertexPos(const T& vertex){ SeqListIterator<T> liter(vertexList); int pos = 0;while(!liter.EndOfList( ) && liter.Data( ) != vertex) { pos++; liter.Next( ); } if (liter.EndOfList( )) { cerr << "GetVertex: the vertex is not in the graph." << endl; pos = -1; } return pos;}

template <class T>int Graph<T>::GetWeight(const T& vertex1, const T& vertex2){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "GetWeight: a vertex is not in the graph." << endl; return -1; } return edge[pos1][pos2];}

template <class T>SeqList<T>& Graph<T>::GetNeighbors(const T& vertex){ SeqList<T> *L; SeqListIterator<T> viter(vertexList);L = new SeqList<T>; int pos = GetVertexPos(vertex); if (pos == -1) { cerr << "GetNeighbors: the vertex is not in the graph." << endl; return *L; } for (int i = 0; i < graphsize; i++) { if (edge[pos][i] > 0) L->Insert(viter.Data( ));viter.Next( ); } return *L;}

template <class T>int Graph<T>::GetFirstNeighbor(const int v){if (v <0||v>graphsize) { cerr << “The vertex is not in the graph." << endl; return -1; } for(int i = 0; i < graphsize;i++) if(edge[v][i] >0) return i; return -1;}

template <class T>int Graph<T>::GetNextNeighbor(const int v, const int v1){if (v <0||v>graphsize ||v1 <0||v1>graphsize) { cerr << “The vertex is not in the graph." << endl; return -1; } for(int i = v1+1; i < graphsize;i++）if(edge[v][i] >0) return i; return -1;}

template <class T>void Graph<T>::InsertVertex(const T& vertex){ if (graphsize+1 > MaxGraphSize) { cerr << "Graph is full" << endl; exit (1); }vertexList.Insert(vertex);graphsize++;}

template <class T>void Graph<T>::InsertEdge(const T& vertex1, const T& vertex2, int weight){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "InsertEdge: a vertex is not in the graph." << endl; return; } edge[pos1][pos2] = weight;}

pos

I

II

pos

III

IV

template <class T>void Graph<T>::DeleteVertex(const T& vertex){ int pos = GetVertexPos(vertex); int row, col; if (pos == -1) { cerr << "DeleteVertex: a vertex is not in the graph." << endl; return; }vertexList.Delete(vertex); graphsize--; for (row = 0; row < pos; row++) for (col = pos + 1;col < graphsize;col++)edge[row][col-1] = edge[row][col]; for (row = pos + 1;row < graphsize;row++) for (col = pos + 1;col < graphsize;col++)edge[row-1][col-1] = edge[row][col]; for (row = pos + 1;row < graphsize;row++) for (col = 0; col < pos; col++)edge[row-1][col] = edge[row][col]; }

template <class T>void Graph<T>::DeleteEdge(const T& vertex1, const T& vertex2){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "DeleteEdge: a vertex is not in the graph." << endl; return; }edge[pos1][pos2] = 0;}

template <class T>int Graph<T>::FindVertex(SeqList<T> &L, const T& vertex){ SeqListIterator<T> iter(L); int ret = 0; while(!iter.EndOfList( )) { if (iter.Data( ) == vertex) { ret = 1; break; }iter.Next( ); } return ret;}

template <class T >class VertexIterator: public SeqListIterator< T >{ public:VertexIterator(Graph< T >& G);};

template <class T >VertexIterator<T>::VertexIterator(Graph<T>& G): SeqListIterator< T > (G.vertexList){}

（如 未标记）

}

ABCDEIHF

A

F

B

C

E

H

D

I

template <class T>

SeqList<T>& Graph<T>::DFS( )

{ int *visited=new int[graphsize];

for(int i=0;i<graphsize;i++)

visited[i]=0;

SeqList<T> *L=new SeqList<T>;

*L=DFS(0,visited);

delete[]visited;

return *L;

}

template <class T>

SeqList<T>& Graph<T>::DFS(const int v, int *visited)

{ SeqList<T>*L;

Tvertex=vertexList.GetData(v);

L=new SeqList<T>;

visited[v]=1;

L->Insert(vertex);

int w=GetFirstNeighbor(v)

while(w!=-1)

{if(!visited[w])DFS(w,visited);

w=GetNextNeihbor(v,w);

}

return *L；

}

//深度优先搜索2 不用递归用栈

L

F

B

A

S

SeqList<T> L; //输出顶点

Stack<T> S; //存储待算顶点

HE

B

AF

IE

B

A

AFH

F

B

D

B

AFHIE

C

E

H

C

AFHIEDB

D

I

AFHIEDBC

//深度优先搜索2 不用递归用栈

template <class T>SeqList<T> & Graph<T>::DepthFirstSearch(const T& beginVertex){ Stack<T> S; SeqList<T> *L, adjL; SeqListIterator<T> iteradjL(adjL); Tvertex; L = new SeqList<T>; S.Push(beginVertex);

ABFCHEDI

Queue<T> Q;

L

Q

BF

A

AB

FCH

A

ABF

CHE

F

B

HED

ABFC

C

E

H

EDI

ABFCH

D

I

ABFCHEDI

template <class T>void PrintList(SeqList<T> &L){ SeqListIterator<T> liter(L);for (liter.Reset( ); !liter.EndOfList( ); liter.Next( )) cout << liter.Data( ) << " ";}

template <class T>int PathConnect (Graph<T> &G, Tv, Tw){ SeqList<T> L;// find vertices connected to vL = G.DepthFirstSearch(v);// is w is in the list, return TRUE if (L.Find(w)) return 1; else return 0;}

template <class T>void UConnectedComponent (Graph<T> &G){ VertexIterator<T> viter(G); SeqList<T> markedList, L; for (viter.Reset( ); !viter.EndOfList( ); viter.Next( )) { if (!markedList.Find(viter.Data( ))) { L.ClearList( ); L = G.DepthFirstSearch(viter.Data( )); SeqListIterator<T> liter(L); for(liter.Reset( );!liter.EndOfList( );liter.Next( ))markedList.Insert(liter.Data( ));PrintList(L); cout << endl; } } }

B

ABC

D

EFG

H

I

A

D

C

F

E

H

G

I

template <class T>void ConnectedComponent (Graph<T> &G){ VertexIterator<T> viter(G); SeqList<T> markedList, scList, L; for (viter.Reset( ); !viter.EndOfList( ); viter.Next( )) { if (!markedList.Find(viter.Data( ))) { scList.ClearList( );L = G.DepthFirstSearch(viter.Data( )); SeqListIterator<T> liter(L);

for (liter.Reset( );!liter.EndOfList( );liter.Next( )) if (PathConnect(G,liter.Data( ),viter.Data( ))) { scList.Insert(liter.Data( ));markedList.Insert(liter.Data( )); }PrintList(scList); cout << endl; } }}

Prim 普里姆算法

1. 令 U={v0}, T={ }.

2. 对任意u∈U, v∈V-U, (u,v)∈E,

3. 重复2，直至U=V.

T中共有n-1条边

A

28

F

16

10

14

B

D

H

24

18

25

12

C

E

22

A

28

F

16

10

14

B

D

H

24

18

25

12

C

E

22

A

A

5

5

6

6

1

1

B

D

B

D

5

5

5

5

C

C

4

4

6

2

6

2

3

3

E

F

E

F

6

6

U={A}, T={(A,C)}

U={A,C}, T={(A,C),(C,F)}

U={A,C,F}, T={(A,C),(C,F),(D,F)}

U={A,C,F,D}, T={(A,C),(C,F),(D,F),(B,C)}

U={A,C,F,D,B}, T={(A,C),(C,F),(D,F),(B,C),(B,E)}

U={A,C,F,D,B,E}

A

U中点距离为0，

5

6

1

B

D

5

5

C

4

6

2

3

E

F

6

template<class T>struct MiniCostEdgeInfo { Tadjvex; int lowcost; };template <class T>int operator<(MiniCostEdgeInfo<T> a, MiniCostEdgeInfo<T> b){ return a.lowcost<b.lowcost;}

template <class T>int minimum(MiniCostEdgeInfo<T> *a,int n){ for(int i=0;i<n;i++) if(a[i].lowcost!=0) break; int min=i; for(i=min+1;i<n;i++) if(a[i].lowcost!=0&&a[i]<a[min]) min=i ; return min;}

template<class T>T GetVertex(Graph<T> G,int pos){ int i, n=G.NumberOfVertices( ); if(pos<0||pos>=n) {cerr<<"There are not so many vertices!"; return 0; } VertexIterator<T> liter(G);i = 0; while(!liter.EndOfList( ) && i != pos) { i++;liter.Next( ); } return liter.Data( );}

template<class T >void MiniSpanTreePrim(Graph< T > G){ int j,k,l,n=G.NumberOfVertices( ); MiniCostEdgeInfo< T > * closeEdge;closeEdge =new MiniCostEdgeInfo< T >[n];Ts,w, v=GetVertex(G,0); closeEdge[0].lowcost=0;//起始点v0加进U for(int i=1;i<n;i++)//初始化closeEdge数组{ w=GetVertex(G,i); l=G.GetWeight(v,w);closeEdge[i].adjvex=v; if(l>0)closeEdge[i].lowcost=l; else closeEdge[i].lowcost=maxint; }

for( i=1;i<n;i++) //双重循环复杂度O(n2)与边数无关{ k=minimum(closeEdge,n);//确定closeEdge中最小值v=closeEdge[k].adjvex;//取出这一边w=GetVertex(G,k); l=closeEdge[k].lowcost; cout<<“\n”<<v<<“ ”<<w<<“ ”<<l<<endl;closeEdge[k].lowcost=0; //将w加进U for( j=0;j<n;j++) //更新closeEdge { v=GetVertex(G,j); l=G.GetWeight(w,v); if(l>0&&l<closeEdge[j].lowcost) { closeEdge[j].lowcost=l;closeEdge[j].adjvex=w; } } } }

Kruskal 克鲁斯卡尔算法

G=(V,E) 连通图

• 选择E中权值最小的边，

• 重复1 n-1次直到T连通。

T 就是最小生成树

A

A

5

5

6

6

1

1

1

B

D

5

5

B

D

5

5

5

C

C

4

6

2

4

4

3

6

2

2

3

3

E

F

E

F

6

6

T={ (A,C), (D,F), (B,E) }

T={ (A,C), (D,F), (B,E), (C,F) }

T={ (A,C), (D,F), (B,E)

(C,F), (B,C) }

A

B

D

C

E

F

Kruskal 克鲁斯卡尔算法

1.如何判断两端点是否在同一 分支？

2.如何把两个分支连到一起？

A

B

D

C

E

F

D

B

A

C

F

G

E

H

B

A

D

B

A

D

C

E

C

F

G

E

F

G

H

H

D

A

B

C

E

F

G

H

G的双亲改为2

D

A

B

C

E

F

G

H

0≠2，根不同，分支不同。

A

B

C

D

E

F

G

H

#define MAX_TREE_SIZE 100

template <class T>

struct PNode

{ T data;

int Parent;

}

template <class T>

class PTree

{ PNode<T> nodes[MAX_TREE_SIZE];

int n; //number of nodes

public:

PTree( int m=0);

PNode<T> operator[ ](int i);

int PTreeInsert(T item, int pr);

T PTreeDelete(int i);

int PTreeSize( );

}

#include"ptree.h"template<class T>class MFSet:public PTree< T >{ public:MFSet( ){ } int Find(Titem); int FindRoot(int i); int FindRoot(Titem); void Merge(int root1,int root2);};

template <class T >int MFSet< T >::Find(Titem){ for(int i=0;i<n;i++) if(nodes[i].data==item) { return i; break;} return -1;}template <class T >int MFSet< T >::FindRoot(int i) { if(i<0||i>=n)return -1; for(int j=i;nodes[j].parent>=0;j=nodes[j].parent)；return j; }

template <class T >int MFSet< T >::FindRoot(Titem){ int i=Find(item); return FindRoot(i);}template <class T >void MFSet< T >::Merge(int root1, int root2){ if(root1<0||root1>=n||root2<1||root2>=n) { cerr<<"Beyound the scope!"; } nodes[root2].parent=root1;}

#include<graph.h>#include<conncomp.h>#define maxint 32767template <class T>struct EdgeInfo{ TbeginVex, endVex; int cost;};

//Kruskal算法#define MaxInt 32767#include"APQueue.h"#include"Graph.h"#include"edgeinfo.h"#include"mfset.h"#include"PTree.h"typedefEdgeInfo<char> EI;

template <class T>void MiniSpanTreeKruskal(Graph< T > G){ int i, j, l, n=G.NumberOfVertices( );Titem,u,v; EI edge; MFSet< T > MFS; PQueue<EI> L; for(i=0;i<n;i++) { item=GetVertex(G,i); MFS.PTreeInsert(item,-1); }

for(i=0;i<n;i++) { u=GetVertex(G,i); for(j=0;j<n;j++) { v=GetVertex(G,j);l=G.GetWeight(u,v); if(l!=MaxInt&&l>0) { edge.beginVex=u;edge.endVex=v;edge.cost=l; L.PQInsert(edge); } } }

int count=1; while(count<n) { edge=L.PQDelete( );i=MFS.FindRoot(edge.beginVex); j=MFS.FindRoot(edge.endVex); if(i!=j) { cout<<edge.beginVex<<" "<<edge.endVex <<" "<<edge.cost<<endl;MFS.Merge(i,j); count++; } }}

void main( ){ Graph<char> G;G.ReadGraph("sctest.dat"); cout<<endl; cout<<endl; cout<<endl;MiniSpanTreeKruskal(G);}

4

4

E

A

2

B

4

6

12

6

6

10

8

12

F

D

C

20

14

v5

60

100

30

v4

v0

(v0,v2) 10

10

20

(v0,v4,v3) 50

10

(v0,v4) 30

v3

v1

(v0,v4,v3,v5) 60

5

50

v2

D[i]=从源点v0到顶点vi最短路经的长度。

D[j1]是v0到vj1的最短路径的长度。

L={v0}

v5

60

j1=2

D[2]=10

100

30

v4

v0

10

20

10

v3

v1

5

50

v2

L={v0,v2}

L={v0,v2}

v5

60

100

30

j2=4

D[4]=30

v4

v0

10

20

10

v3

v1

5

50

v2

L={v0,v2,v4}

D[i]=min{D[i], D[jk]+arc[jk][i]}

D[jk+1]=min{D[i], i<n,i≠ j1 ,j2···,jk }

D[jk+1]是v0到vjk+1的最短路径的长.

v5

60

100

L={v0,v2,v4,v3,v5}

30

v4

v0

10

20

10

v3

v1

5

50

v2

template <class T >int operator <= (const PathInfo< T >& a,

const PathInfo< T >& b){ return a.cost <= b.cost;}

//用优先序列实现最短路径算法template <class T >int Graph< T >::MinimumPath(const T & sVertex, const T & eVertex){ PQueue< PathInfo< T > > PQ(MaxGraphSize); PathInfo< T > pathData; SeqList< T > L, adjL; SeqListIterator< T > adjLiter(adjL);Tsv, ev; int mincost;

pathData.startV = sVertex; pathData.endV = sVertex;pathData.cost = 0; PQ.PQInsert(pathData); while (!PQ.PQEmpty( )) { pathData = PQ.PQDelete( ); ev = pathData.endV;mincost = pathData.cost; if (ev == eVertex) break; if (!FindVertex(L,ev)) {L.Insert(ev); sv = ev;adjL = GetNeighbors(sv);adjLiter.SetList(adjL);

for(adjLiter.Reset( );!adjLiter.EndOfList( ); adjLiter.Next( )) { ev = adjLiter.Data( ); if (!FindVertex(L,ev)) { pathData.startV = sv; pathData.endV = ev;pathData.cost = mincost+GetWeight(sv,ev); PQ.PQInsert(pathData); } } } }if (ev == eVertex) return mincost; else return -1;}

template<class T>T GetVertex(Graph<T> G,int pos){ int i, n=G.NumberOfVertices( ); if(pos<0||pos>=n) {cerr<<"There are not so many vertices!"; return 0; } VertexIterator<T> liter(G);i = 0; while(!liter.EndOfList( ) && i != pos) { i++;liter.Next( ); } return liter.Data( );}

template<class T>void ShortestPathDijkstra(Graph<T> G, int v0,int *D,int**P){ int i, j,k,l,min, n=G.NumberOfVertices( );Tu,v,w;u=GetVertex(G,v0); int *final=new int[n]; for( i=0;i<n;i++) { final[i]=0;v=GetVertex(G,i); for(j=0;j<n;j++)P[i][j]=0;//initial P[i][j]D[i]=G.GetWeight(u,v); //initial D[i] if(D[i]<MaxInt){ P[i][v0]=1;P[i][i]=1;}// p[i][j]=1 iff vertex j is in the path from v0 to i }

D[v0]=0; final[v0]=1; for(i=1;i<n;i++) { min=MaxInt; for(j=1;j<n;j++) //Get the minimum D[k] if(final[j]==0) //vertex j has not marked. if(D[j]<min) { k=j; min=D[j];}final[k]=1; //marked vertex k, v=GetVertex(G,k); //found the shortest path for(j=1;j<n;j++) { w=GetVertex(G,j); l=G.GetWeight(v,w)+min; if(!final[j]&&(l<D[w])) { D[w]=l; //renew D[w]P[j]=P[k]; P[j][j]=1; } } } }

void main( ){ Graph<char> G;G.ReadGraph("sctest.dat"); int n=G.NumberOfVertices( ); int *D=new int[n]; int **P=new (int**[n])[n];ShortestPathDijkstra(G,0,D,P); for(int i=0;i<n;i++) { cout<<"P["<<i<<"]={ "; cout<<P[i][0]; for(int j=1;j<n;j++) cout<<","<<P[i][j]; cout<<"}"<<endl; }}

6

v0

v1

4

11

2

3

v2

int **D=new (int**[n])[n];

int ***P= new ((int***[n])[n])[n];

D-1[i][j]=arc[i][j];

Dk[i][j]=min{Dk-1[i][j], Dk-1[i][k]+ Dk-1[k][j]}

#include"graph.h"#define MaxInt 32767typedef int** DistanceMatrix;typedef int** PathMatrix;

template <class T>void ShortestPathFloyd( Graph<T> G,PathMatrix *&P, DistanceMatrix& D){ int n=G.NumberOfVertices( ); int i,j,k,l,t; Tu,v,w; for(i=0;i<n;i++) { u=GetVertex(G,i); for(j=0;j<n;j++) { v=GetVertex(G,j);D[i][j]=MaxInt;l=G.GetWeight(u,v); if(l>0)D[i][j]=l; for(k=0;k<n;k++) P[i][j][k]=0; if(D[i][j]<MaxInt) {P[i][j][i]=1;P[i][j][j]=1;} }

for(k=0;k<n;k++) for(i=0;i<n;i++) for(j=0;j<n;j++) if(D[i][k]+D[k][j]<D[i][j]) { D[i][j]=D[i][k]+D[k][j]; for(t=0;t<n;t++)P[i][j][t]=P[i][k][t]||P[k][j][t]; } }}

void main( ) { Graph<char> G;G.ReadGraph("sctest.dat"); int n=G.NumberOfVertices( ); DistanceMatrix D=new (int** [n])[n]; PathMatrix* P=new (int***)[n]; for(int i=0;i<n;i++)P[i]=new (int** [n])[n];ShortestPathFloyd(G,P,D); for( i=0;i<n;i++) {cout<<endl; for(int j=0;j<n;j++) cout<<D[i][j]<< " "; } }

AOV网Activity on Vertex Network

ABCDEF

ACDEBF

B

A

F

C

D

E

1. 选择一个没有前驱的顶点输出，

2. 去掉这个顶点以及从这点出发的所有边。

• 用一个数组纪录图G的每个顶点的入度
• 找出第一个入度为0的点输出
• 找出与之相连的所有顶点，将他们的入度都减1。
• 重复2.3.直至没有入度为0的点

//入度算法函数

int n=G.NumberOfVertices( );

int indegree[n];

void InDegree(Graph<T> G,*indegree)

{ int i,j=0; T u,v;

for( i =0; i <n; i ++)indegree[i]=0;

for( i =0; i <n; i ++)

{u=GetVertex(G, i);

for( j =0; j <n; j ++)

v=GetVertex(G, j);

if(G.GetWeight(u,v))indegree[j]++;}

}

Template<class T>void TopologicalSort(Graph<T> G)

{ int n=G.NumberOfVertices;

int *indegree=new int[n];

Stack<int> S;

InDegree(G,indegree);//纪录顶点的入度

for(int i=0;i<n;i++) if(indegree[i]==0)S.Push(i);

int count=0; //入度为0的点进栈

while(!S.StackEmpty( ))

{ i=S.Pop( ); //取出一个入度0的点输出

cout<<GetVertex(G,i)<<“ ”; ++count;

for(int j=G.GetFirstNeighber(i);j>0;

j= G.GetNextNeighber(i,j))

if(--indegree[j]==0)S.Push(j); //邻接点入度减1}

if(count<n)cout<<“There is a circle!”;

}

AOE网 工程进度表示

AOE网 Active on Edges

v2

v7

a1=6

a4=1

a7=9

a10=2

v5

v1

v9

a5=1

a2=4

a8=7

a11=4

v8

v3

a3=5

a9=4

a6=2

v4

v6

AOE网的关键路径critical path

（起点） （终点）

v2

v7

a1=6

a4=1

a7=9

a10=2

v5

v1

v9

a5=1

a2=4

a8=7

a11=4

v8

v3

a9=4

a3=5

a6=2

v4

v6

ve(i) vi的最早开始时间=v1到vi的最长路径

ve(n)=工程完成时间

vl(i) vi的最迟开始时间=vn-vi到vn的最长路径

e(k) 活动ak的最早开始时间

l(k) 活动ak的最迟开始时间

l(k)-e(k) 活动ak的松弛时间 slack time

ve(i),vl(i)的递归算法（以拓扑排序递归）

ve(0)=0;

ve(j)=max{ ve(i)+dut<i,j>}

<i,j>∈T

dut<i,j> =边ak=<vi,vj>的长

T是所有以vj为终点的边的集合

vl(n-1)=ve(n-1)

vl(i)=min{vl(j)-dut<i,j>}

<i,j>∈S

S是所有以vi为起点的边的集合

v2

v7

a1=6

a4=1

a7=9

a10=2

v5

v1

v9

a5=1

a2=4

a8=7

a11=4

v8

v3

a3=5

a9=4

a6=2

v4

v6

Template<class T>void CriticalPath(Graph<T> G)

{ int i,j, l,ee,el,tag,n=G.NumberOfVertices;

int *indegree=new int[n];

int *ve=new int[n];

int *vl=new int[n];

Stack<int> S1,S2; Tu,v;

InDegree(G,indegree);//纪录顶点的入度

for(i=0;i<n;i++) if(indegree[i]==0)S.Push(i);

int count=0; //入度为0的点进栈

while(!S.StackEmpty( ))

{ i=S.Pop( ); //取出一个入度0的点输出

T.Push(i);

++count;

for(j=G.GetFirstNeighber(i); j>0;

j= G.GetNextNeighber(i,j))

if(--indegree[j]==0)S.Push(j); //邻接点入度减1

u=GetVertex(G,i); v=GetVertex(G,j);

l=ve[i]+G.GetWeight(u,v);

if(l>ve[j])ve[j]=l;

}

if(count<n)cout<<“There is a circle!”;

for( i=0;i<n;i++)

vl[i]=ve[i]; //初始化vl[I]

while(!T.StackEmpty( ))

for(i=T.Pop( ), j=G.GetFirstNeighber(i); j>0;

j= G.GetNextNeighber(i,j))

{ u=GetVertex(G,i); v=GetVertex(G,j);

l=vl[j]-G.GetWeight(u,v);

if(l<vl[i])vl[i]=l; }

for( i=0;i<n;i++)

for(j=G.GetFirstNeighber(i); j>0;

j= G.GetNextNeighber(i,j))

{ u=GetVertex(G,i); v=GetVertex(G,j);

l=G.GetWeight(u,v); ee=ve[i]; el=vl[j]-l;

tag= (ee==el)? ‘*’: ‘ ’；

cout<<u<<“ ”<<v<<“ ”

<<ee<<“ ”<<el<<“ ”<<tag<<endl;}

}