圖
一.思維導圖
(PowerPoint製作畫面小,字型較小將就觀看)
二.圖的知識內容
1.圖的基本概念
1.1圖的定義
圖(Graph)是由頂點的有窮非空集合和頂點之間邊的集合組成。通常表示為:G(V,E),G表示一個圖,V是圖G中頂點的集合,E是圖G中邊的集合。
無向圖
如果圖中任意兩個頂點之間的邊都是無向邊,則稱該圖為無向圖。
有向圖
如果圖中任意兩個頂點之間的邊都是有向邊,則稱該圖為有向圖。
1.2圖的基本術語
端點和鄰接點:兩頂點為一條邊的端點時,這兩點互稱為鄰接點。
頂點的度、入度和出度:在無向圖中,一個頂點所關聯的邊的數目稱為該頂點的度(degree)。在有向圖中,頂點度又分為入度和出度,以頂點j為終點的邊數目,稱為該頂點的入度(indegree)。以頂點i點的邊數目,稱為該頂點的出度(outdegree)。一個頂點的入度與出度的和為該頂點的度。(一個圖中所有頂點的度之和等於邊數的兩倍)
完全圖:若無向圖中的每兩個頂點之間都存在著一條邊,有向圖中的每兩個頂點之間都存在著方向相反的西條邊稱此圖為完全圖(completed graph)。顯然,無向完全圖包含有n(n-1)/2條邊,有向圖包含有你n(n-1)條邊。
稠密圖和稀疏圖:當一個圖接近完全圖時,稱為稠密圖(dense graph),相反,當一個圖含有較少的邊數(如e<nlog2n)時,則稱為稀疏圖(sparse graph)。
子圖:設有兩個圖G=(V,E)和G'=(V,E'),若V'是V的子集,即V'包含於V,且E是E的子集即E'包含於E,則稱G'是G的子圖(subgraph)。
路徑和路徑長短:設圖G=(V,{E})中的一個頂點序列{u=Fi0,Fi1,Fi2,….Fim=w}中,(Fi,j-1,Fi,j)∈E 1 ≤j ≤m,則稱從頂點u到頂點w之間存在一條路徑,路徑上邊或弧的數目稱作路徑長度,
若路徑中的頂點不重複出現的路徑稱為簡單路徑
若路徑中第一個頂點到最後一個頂點相同的路徑稱為迴路或環
若路徑中第一個頂點和最後一個頂點之外,其餘頂點不重複出現的迴路,稱為簡單迴路或簡單環。
迴路或環:若一條路徑上的開始點與結束點為同一個頂點,則此路徑被稱為迴路或環(cycle)。開始點與結束點相同的簡單路徑被稱為簡單迴路或簡單環(simple cycle)。
聯通、連通圖和聯通分量:
連通圖
在無向圖G(V,{E})中,如果從頂點V到頂點W有路徑,則稱V和W是連通的。如果對於圖中任意兩個頂點Vi、Vj∈V,Vi和Vj都是連通的,則稱G是連通圖。
連通分量
若無向圖為非連通圖,則圖中各個極大連通子圖稱作此圖的連通分量。
強連通圖和強聯通分量:
強連通圖
在有向圖G(V,{E})中,如果對於每一對Vi ,Vj∈V,Vi≠Vj,從Vi到Vj和從Vj到Vi都存在有向路徑,則稱G是強連通圖。(n個頂點強聯通圖至少有n條邊)
強連通分量
若有向圖不是強連通圖,則圖中各個極大強連通子圖稱作此圖的強連通分量。
權和網:圖中的每一條邊都可以附有一個對應的數值,這種與邊相關的數值稱為權。權可順示從一個頂點到另一個頂點的距離或花費的代價。邊上帶有權的圖稱為帶權圖(weihgraph),也稱作網(net)。
2.圖的儲存結構和基本運算演算法
2.1鄰接矩陣儲存方法
如下圖(老師課件)
/*圖的鄰接矩陣儲存*/
typedef int VertexType;
typedef int EdgeType;
#define MAXVEX 100
#define INFI 65535
typedef struct
{
VertexType vexs[MAXVEX]; /*頂點表*/
EdgeType matrix[MAXVEX][MAXVEX]; /*鄰接矩陣*/
unsigned int numVertexes; /*頂點數*/
unsigned int numEdges; /*邊數*/
}Graph;
2.2鄰接表儲存方式
如下圖(老師課件)
2.3圖的基本運算演算法設計
建立圖的運算演算法
輸出圖的運算演算法
銷燬圖的運算演算法
程式碼詳見課本260頁。
3.圖的遍歷
3.1圖的遍歷概念
圖建構好後,針對具體的問題,我們常常需要通盤的讀取圖中的資訊,包括頂點(vertex)和邊(edge),以及它們之間的關係。這種讀取圖中所有資訊的方法就是圖的遍歷(traversal),也稱為搜尋(search),就是從圖中某個頂點出發,沿著一些邊訪問圖中所有的頂點,且使每個頂點僅被訪問一次。遍歷是很多圖論演算法的基礎。根據搜尋方法的不同,圖的遍歷分為兩種:深度優先遍歷(DFS)、廣度優先遍歷(BFS)。
3.2深度優先遍歷和廣度優先遍歷
遍歷需要圖形結合來理解,為了更好理解推薦一篇遍歷連結給你們
遍歷連結
個人理解:深度遍歷一個節點接一個節點遍歷,不遍歷已遍歷過的節點。廣度遍歷先從初始點出發,連線他的節點都要遍歷,然後遍歷連線初始點的節點的節點,依此類推。
4.生成樹和最小生成樹
4.1生成樹的概念
在一個任意連通圖G中,如果取它的全部頂點和一部分邊構成一個子圖G',即:V(G')=V(G)和E(G')⊆E(G)
若同時滿足邊集E(G')中的所有邊既能夠使全部頂點連通而又不形成任何迴路,則稱子圖G'是原圖G的一棵生成樹。
4.2無向圖的聯通分量和生成樹
詳見課本280頁。
4.3普里姆演算法、克魯斯卡爾演算法
普里姆演算法:適用於稠密
克魯斯卡爾演算法:適用於稀疏
我覺得這篇部落格不錯,很好理解,複習用的上。
演算法連結
5.最短路徑
5.1路徑的概念
在一個不帶權圖中,若從一頂點到另一頂點存在著一條路徑,則稱該路
徑長度為該路徑上所經過的邊的數目,它等於該路徑上的頂點數減1。由
於從一頂點到另一頂點可能存在著多條路徑,每條路徑上所經過的邊數可能不同,即路徑長度不同,把路徑長度最短(即經過的邊數最少)的那條路徑稱為最短遊(shortest path),其長度稱為最短路徑長度或最短距離。對於帶權圖,考慮路徑上各邊上的權,則把一條路徑上所經邊的權之和定義為該路制路徑長度。從源點到終點可能有不止一條路徑,把路徑長度最小的那條路徑稱為最短路徑其路徑長度(權之和)稱為最短路徑長度。實際上,只要把不帶權圖上的每條邊看成是權值為1的邊,那麼不帶權圖和帶權圖的最短路徑和最短距離的定義就一致了。
5.2從一個頂點到其餘各頂點的最短路徑
Dijkstra演算法介紹
演算法特點:
迪科斯徹演算法使用了廣度優先搜尋解決賦權有向圖或者無向圖的單源最短路徑問題,演算法最終得到一個最短路徑樹。該演算法常用於路由演算法或者作為其他圖演算法的一個子模組。
演算法的思路
Dijkstra演算法採用的是一種貪心的策略,宣告一個陣列dis來儲存源點到各個頂點的最短距離和一個儲存已經找到了最短路徑的頂點的集合:T,初始時,原點 s 的路徑權重被賦為 0 (dis[s] = 0)。若對於頂點 s 存在能直接到達的邊(s,m),則把dis[m]設為w(s, m),同時把所有其他(s不能直接到達的)頂點的路徑長度設為無窮大。初始時,集合T只有頂點s。
然後,從dis陣列選擇最小值,則該值就是源點s到該值對應的頂點的最短路徑,並且把該點加入到T中,OK,此時完成一個頂點,
然後,我們需要看看新加入的頂點是否可以到達其他頂點並且看看通過該頂點到達其他點的路徑長度是否比源點直接到達短,如果是,那麼就替換這些頂點在dis中的值。
然後,又從dis中找出最小值,重複上述動作,直到T中包含了圖的所有頂點。
原文連結,很詳細
5.3每對頂點之間的最短路徑
6.AOE網與關鍵路徑
6.1相關概念
在一個表示工程的帶權有向圖中,用頂點表示事件,用有向邊表示活動,用邊上的權值表示活動的持續時間,這種有向圖的邊表示活動的網,稱之為AOE網(Activity On edge Network)。由於一個工程,總有一個開始,一個結束,在正常情況下,AOE網只有一個源點一個匯點。入度為零的為開始事件,出度為零的為結束事件,關鍵活動不存在富餘時間,一個AOE網可能存在多個關鍵路徑,但是他們的長度相同。
6.2求AOE網的關鍵活動
詳見課本的306頁(講解困難,能力不足)。
三.疑難問題
有了一張自駕旅遊路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。現在需要你寫一個程式,幫助前來諮詢的遊客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那麼需要輸出最便宜的一條路徑。
輸入格式:
輸入說明:輸入資料的第1行給出4個正整數N、M、S、D,其中N(2≤N≤500)是城市的個數,順便假設城市的編號為0~(N−1);M是高速公路的條數;S是出發地的城市編號;D是目的地的城市編號。隨後的M行中,每行給出一條高速公路的資訊,分別是:城市1、城市2、高速公路長度、收費額,中間用空格分開,數字均為整數且不超過500。輸入保證解的存在。
輸出格式:
在一行裡輸出路徑的長度和收費總額,數字間以空格分隔,輸出結尾不能有多餘空格。
輸入樣例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
輸出樣例:
3 40
include<bits/stdc++.h>
using namespace std;
#define INF 65535
struct Node {
int len, price;
};
int N, M, S, D, Dist[505], Price[505] = {0};
Node G[505][505];
bool visit[505] = {false};
int main() {
cin >> N >> M >> S >> D;
int v, u, l, p;
fill(Dist, Dist + N, INF);
fill(Price, Price + N, INF);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++) {
G[i][j].len = INF;
G[i][j].price = INF;
}
for (int i = 0; i < M; i++) {
cin >> v >> u >> l >> p;
G[v][u].len = G[u][v].len = l;
G[v][u].price = G[u][v].price = p;
}
Dist[S] = 0;
Price[S] = 0;
for (int i = 0; i < N; i++) {
int V = -1, Min = INF;
for (int j = 0; j < N; j++) {
if (Dist[j] < Min && !visit[j]){
V = j;
Min = Dist[j];
}
}
if (V == -1) break;
visit[V] = true;
if (V == D) {
cout << Dist[V] << " " << Price[V];
break;
}
for (int j = 0; j < N; j++) {
if (!visit[j] && Dist[V] + G[V][j].len < Dist[j]) {
Dist[j] = Dist[V] + G[V][j].len;
Price[j] = Price[V] + G[V][j].price;
} else if (!visit[j] && Dist[V] + G[V][j].len == Dist[j]) {
if (Price[j] > Price[V] + G[V][j].price) Price[j] = Price[V] + G[V][j].price;
}
}
}
return 0;
}
總結,要解出一道題,要有身厚的功底,不懂的知識要及時看書,實在不懂csdn輔助理解,同學一起解決。
本題要用到dijstra演算法,Dijkstra的本質就是如果收錄v使得s到w的距離變短,則s到w的最短路一定經過v。
本題要注意:儲存圖的時候節點編號從1開始。
鄰接矩陣儲存的圖。
初始化時把每個節點初始化成最遠距離。