Graph Theory
Ian Wen
基本定義 & 名詞介紹
存圖
圖的遍歷 (Traversal)
1. 圖 (Graph)
2. 點 (Vertex) & 邊 (Edge)
3. 路徑 (Path)
4. 圖的分類
基本定義 & 名詞介紹
圖 (Graph)
你聽過的 "圖" ?
- 教育部國語辭典重編本
基本定義 & 名詞介紹
圖 (Graph)
Definition
在離散數學中,圖(英語:graph)是用於表示物體與物體之間存在某種關係的結構。
- 維基百科
基本定義 & 名詞介紹
圖 (Graph)
一張圖是由點 (Vertex) 與邊 (Edge) 構成的集合
一張圖
Definition
基本定義 & 名詞介紹
邊 (Edge)
以 (u, v) 表示,代表有一條邊連接 點u 與 點v
邊可以有/無方向,有方向時用箭頭表示
邊權:邊上帶的權重
10
7
5
重邊:多條邊 (u, v) 相同
自環:u = v
基本定義 & 名詞介紹
度數
點權
點 (Vertex)
1(20)
2(15)
3(9)
4(7)
度數為 1,權重 9
基本定義 & 名詞介紹
路徑 (Path)
基本定義 & 名詞介紹
一些圖的分類
基本定義 & 名詞介紹
一些圖的分類
4. 完全圖:所有點跟點之間都有邊,且為簡單圖
基本定義 & 名詞介紹
一些圖的分類
5. 子圖:所有點 & 邊都存在於原圖中
基本定義 & 名詞介紹
一些圖的分類
6. 補圖:兩圖點相同,聯集兩圖的邊會變成完全圖
基本定義 & 名詞介紹
一些圖的分類
7. 樹:無環無向連通圖
基本定義 & 名詞介紹
一些圖的分類
8. 稀疏圖: ex:樹
9. 稠密圖: ex:完全圖
$$|E| > |V|log|V|$$
$$|E| \leq |V|log|V|$$
基本定義 & 名詞介紹
啊哈,想不到會有題目吧
1. 鄰接矩陣
2. 鄰接陣列
3. 網格座標
存圖
Adjacency Matrix
鄰接矩陣
0
2
3
1
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0 | 0 | 1 | 0 |
1 | 0 | 0 | 0 | 1 |
2 | 1 | 0 | 0 | 1 |
3 | 0 | 1 | 1 | 0 |
建一個 大小的表,儲存 (u, v) 有沒有邊/邊權
$$|V|^2$$
無向圖記得 (u, v) (v, u) 要存兩次
存圖
int n, m;
cin >> n >> m;
vector<vector<bool>> graph(n, vector<bool>(n, 0));
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
graph[u][v] = 1;
graph[v][u] = 1;
}
Adjacency Matrix
實作
存圖
Adjacency List
鄰接陣列
0
2
3
1
Graph = {
{2},
{3},
{0, 3},
{1, 2}
}
graph[u] 中存的是 u 點連到的點集
無向圖記得 (u, v) (v, u) 要存兩次
存圖
int n, m;
cin >> n >> m;
vector<vector<int>> graph(n);
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
Adjacency List
實作
存圖
鄰接矩陣
鄰接陣列
存圖
網格座標
就是一個二維的網格,格子是點,與四邊的格子連通
就數學題目上會看到的那種
存圖
網格座標
實作?
開個二維陣列就好了 =-=
1. 深度優先搜尋 (DFS)
2. 廣度優先搜尋 (BFS)
3. 網格座標
4. 例題
圖的遍歷 (Traversal)
還記得枚舉的決策🌲嗎?
🌲?圖論!
把一條路走到底再走其他的路
圖的遍歷 (Traversal)
深度優先搜尋 (DFS)
0
2
3
1
5
4
6
DFS實作
遞迴
vector<vector<int>> graph;
vector<bool> visited;
void dfs(int cur) {
visited[cur] = true;
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) dfs(nxt);
}
}
圖的遍歷 (Traversal)
存圖 & 記錄哪些點走過
DFS實作
遞迴
vector<vector<int>> graph;
vector<bool> visited;
void dfs(int cur) {
visited[cur] = true;
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) dfs(nxt);
}
}
圖的遍歷 (Traversal)
存圖 & 記錄哪些點走過
記錄走過的點
DFS實作
遞迴
vector<vector<int>> graph;
vector<bool> visited;
void dfs(int cur) {
visited[cur] = true;
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) dfs(nxt);
}
}
圖的遍歷 (Traversal)
存圖 & 記錄哪些點走過
記錄走過的點
往其他還沒走過點遞迴下去
圖的遍歷 (Traversal)
DFS 可以幹嘛?
圖的遍歷 (Traversal)
0
2
3
1
5
4
6
淹水問題
水從2開始淹,會怎麼淹到各個點
圖的遍歷 (Traversal)
從起點開始,越近的點先走
廣度優先搜尋 (BFS)
實作?迴圈就可以寫了
vector<vector<int>> graph;
void bfs(int origin) {
queue<int> nexts;
vector<bool> visited;
while(!nexts.empty()) {
int cur = nexts.front();
nexts.pop();
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) {
visited[nxt] = true;
nexts.push(nxt);
}
}
}
}
圖的遍歷 (Traversal)
廣度優先搜尋 (BFS)
vector<vector<int>> graph;
void bfs(int origin) {
queue<int> nexts;
vector<bool> visited;
while(!nexts.empty()) {
int cur = nexts.front();
nexts.pop();
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) {
visited[nxt] = true;
nexts.push(nxt);
}
}
}
}
圖的遍歷 (Traversal)
廣度優先搜尋 (BFS)
小觀察:把 queue 換成 stack 就變成 dfs 了 :D
但沒人會這樣幹,遞迴香
vector<vector<int>> graph;
void bfs(int origin) {
queue<int> nexts;
vector<bool> visited;
while(!nexts.empty()) {
int cur = nexts.front();
nexts.pop();
for (int i = 0; i < graph[cur].size(); i++) {
int nxt = graph[cur][i];
if (!visited[nxt]) {
visited[nxt] = true;
nexts.push(nxt);
}
}
}
}
圖的遍歷 (Traversal)
BFS 可以幹嘛?
圖的遍歷 (Traversal)
但這樣 DFS 很廢的感覺?
圖的遍歷 (Traversal)
網格座標?
#include <iostream>
#include <vector>
using namespace std;
void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
// 記得處理好邊界
if (x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size() || grid[x][y] == 1 || visited[x][y]) {
return;
}
// 走到哪個點
visited[x][y] = true;
cout << "Visited: (" << x << ", " << y << ")" << endl;
// 上下左右走
vector<pair<int,int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (int i=0;i<4;i++) {
int newX = x + dir[i].first;
int newY = y + dir[i].second;
dfs(grid, visited, newX, newY);
}
}
int main() {
// 隨便唬爛一個網格
vector<vector<int>> grid = {
{0, 0, 1},
{0, 1, 0},
{0, 0, 0}
};
int m = grid.size();
int n = grid[0].size();
vector<vector<bool>> visited(m, vector<bool>(n, false));
// 開始 DFS
dfs(grid, visited, 0, 0);
}
DFS 走一個二維陣列:
圖的遍歷 (Traversal)
好欸例題
去好好刷題
圖論好玩的la