GRAPH[0]

Graph Theory

Ian Wen

INDEX

基本定義 & 名詞介紹

存圖

圖的遍歷 (Traversal)

基本定義 & 名詞介紹

1. 圖 (Graph)

2. 點 (Vertex) & 邊 (Edge)

3. 路徑 (Path)

4. 圖的分類

基本定義 & 名詞介紹

圖 (Graph)

你聽過的 "圖" ?

  1. 由各種線條、形狀、色彩等描繪成的形象或畫面。如:「地圖」、「設計圖」、「插圖」、「草圖」。

- 教育部國語辭典重編本

基本定義 & 名詞介紹

圖 (Graph)

Definition

離散數學中,(英語:graph)是用於表示物體與物體之間存在某種關係的結構。

- 維基百科

基本定義 & 名詞介紹

圖 (Graph)

一張圖是由點 (Vertex) 與邊 (Edge) 構成的集合

一張圖

Definition

基本定義 & 名詞介紹

邊 (Edge)

以 (u, v) 表示,代表有一條邊連接 點u 與 點v

邊可以有/無方向,有方向時用箭頭表示

邊權:邊上帶的權重

 

10

7

5

重邊:多條邊 (u, v) 相同

自環:u = v

基本定義 & 名詞介紹

度數

  1. 無向圖:點上接有的邊數
  2. 有向圖
    • 入度:指向該點的邊數
    • 出度:離開該點的邊數 

點權

  • 點上帶有的權重

點 (Vertex)

1(20)

2(15)

3(9)

4(7)

度數為 1,權重 9

基本定義 & 名詞介紹

路徑 (Path)

  1. 點與點之間由邊、點交錯構成的集合 {E, V, ..... V, E}
  2. 簡單路徑:一條不重複經過同一點的路徑
  3. 迴路 (腦迴路):起點終點相同的路徑
  4. 環:迴路同時又是簡單路徑

基本定義 & 名詞介紹

一些圖的分類

  1. 簡單圖 (Simple Graph):沒有重邊、沒有自環的圖
  2. 有向圖 (Directed Graph):邊有方向
    • 強連通:所有點必能走向所有其他的點
    • 弱連通:所有點跟點之間有一條邊 (不一定能走)
    • 有向無環圖 (DAG):顧名思義 有向無環
  3. 無向圖 (Undirected Graph):邊沒有方向
    • 連通圖:所有點跟點之間必有一條邊

基本定義 & 名詞介紹

一些圖的分類

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

實作

存圖

鄰接矩陣

鄰接陣列

  • 快速查看 u, v 間的邊
  • 浪費空間
  • 不好處理重邊
  • 處理稠密圖較有效率
  • 不能直接查看 u, v 間的邊
  • 對於相鄰點的操作方便
  • 比較不浪費空間
  • 處理稀疏圖、稠密圖都很好

存圖

網格座標

就是一個二維的網格,格子是點,與四邊的格子連通

就數學題目上會看到的那種

存圖

網格座標

實作?

開個二維陣列就好了 =-=

圖的遍歷 (Traversal)

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)

  1. 一種方式走過所有連通的點
  2. 可以處理相鄰節點的問題
  3. 可以處理兩點連通的問題

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)

  1. 存圖
  2. nexts: 同一輪遍歷的點集,visited 紀錄走過的點
  3. 當本輪點集還沒遍歷完,繼續遍歷
  4. 遍歷到的點丟出點集
  5. 把遍歷到的點旁邊的點都丟入下一輪要遍歷的點集,紀錄為已走過
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 可以幹嘛?

  1. 一種遍歷圖的方法
  2. 處理相鄰節點的問題
  3. 不帶權時處理最短路問題
    • BFS 直到走到目標點
    • 紀錄好路徑,就是最短

圖的遍歷 (Traversal)

但這樣 DFS 很廢的感覺?

  1. 實作好寫
  2. code 短
  3. 還蠻常用的

圖的遍歷 (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

基礎圖論

By wen Ian

基礎圖論

  • 264