圖論[0]
INFOR 36th. @小海_夢想特急_夢城前
Glossary.
如果你不知道這是啥,這是教育部的解釋
A graph is a structure amounting to a set of objects in which some pairs of the objects are in some sense "related".
「一張圖是一種結構,描述了一個集合中成對物件之間的關聯性。」
「一張圖是一種結構,描述了一個集合中成對物件之間的關聯性。」
結構兩字可以理解成資料結構,雖然它的本意更接近程式中的 object
「一張圖是一種結構,描述了一個集合中成對物件之間的關聯性。」
結構兩字可以理解成資料結構,雖然它的本意更接近程式中的 object
「一張圖是一種結構,描述了一個集合中成對物件之間的關聯性。」
結構兩字可以理解成資料結構,雖然它的本意更接近程式中的 object
「一張圖是一種結構,描述了一個集合中成對物件之間的關聯性。」
結構兩字可以理解成資料結構,雖然它的本意更接近程式中的 object
:點
:邊
點集:點構成的集合,以 表示
邊集:邊構成的集合,以 表示
圖:點和邊構成的集合,以 表示
Path
Trace
Track
Circuit
Cycle
一般做法 或 ,但可以
怪題思考題
Storage.
在開始前,先了解一下我的習慣...
#include <bits/stdc++.h>
using namespace std;
int n; // |V|
int m; // |E|
int u, v, vertex; // 某個點
int e, edge; // 某個邊
int w, weight; // 某個權重
int cur; // 通常是遞迴時現在在哪個點
int pre, prev; // 上一個點
int next, nxt; // 下一個點
vector<vector<type>> graph; // 圖
vector<int> neighbor; // 一個點附近的點
const int INF = 1e9 + 7;
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;
}
空間複雜度?
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);
}
因為這東西比較常用,所以如果後面有 graph 應該都是指鄰接串列的存法
方式 | 鄰接矩陣 | 鄰接串列 |
---|---|---|
空間複雜度 | ||
存取特定邊 | ||
枚舉邊 |
struct Node {
int weight; // 點的資訊
struct Edge {
int v;
int weight; // 邊的資訊
};
vector<Edge> neighbor;
};
vector<Node> graph;
比較少用到的東西
int n, m;
cin >> n >> m;
vector<pair<int, int>> edges;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
edges.push_back({u, v});
}
Traversal.
Graph traversal refers to the process of visiting each node in a graph".
「圖的遍歷代表以某種方式走過圖的每個點」
這次夠白話了吧
等等 是不是哪裡怪怪的
等等 是不是哪裡怪怪的
:那記錄上一個點是誰,然後不要往回走啊
好像還有哪裡怪怪的欸
改成記錄走過的點?
2 號節點表示自己被排擠了
要回溯看看之前的其他點,所以我們採用遞迴
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);
}
}
記得在進點時就要記錄 visited
不然你會兩個點一直來回跳
你會發現,距離越近的點淹得越快
如何知道下一輪要淹哪?
你可以在淹一輪後掃過整個點集
如果這個點有淹水且它的鄰居沒有淹就淹下去
你可以在淹一輪後掃過整個點集
如果這個點有淹水且它的鄰居沒有淹就淹下去
時間複雜度?
時間複雜度?
時間複雜度?
花太多時間決定下一輪淹哪了
時間複雜度?
每個點被經過一次 + 每條邊最多被處理兩次
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);
}
}
}
}
在 push 進 queue 時就要記得 visited!
小觀察:把 queue 換成 stack 就是在 dfs 了
但通常會用遞迴啦 好寫
const int dx[] = {1, 0, -1};
const int dy[] = {1, 0, -1};
void dfs(int cur_x, int cur_y, const vector<vector<int>> &graph) {
vector<vector<bool>> visited(graph.size(), vector<bool> graph[0].size());
for (int i: dx)
for (int j: dy)
if (!visited[cur_x + i][cur_y + j])
visited[cur_x + i][cur_y + j] = true,
dfs(cur_x + i, cur_y + j, graph);
}
把重複的部分換成迴圈
如果你只要上下左右就自己調整吧
二分圖的課時會講更酷的做法
iscoj 4534 (電研一四學術上機考 B3)
補:2023 APCS 10月場 P3 / ZJ m372
但我懶得用 DFS 題解在後面 DSU