22527 鄭竣陽
Brine
BrineTW#7355
Index[0]
Index[1]
Index[2]
Index[3]
Glossary
所以什麼是圖?
邊
的路徑Graph Storage
int main() {
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
vector< vector<bool> > graph;
graph.assign(vertexCount, vector<bool>(vertexCount));
int u, v;
for (int i = 0; i < edgeCount; i++) {
cin >> u >> v;
graph[u][v] = graph[v][u] = 1;
}
}
空間複雜度?
int main() {
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
vector< vector<int> > graph(vertexCount);
int u, v;
for (int i = 0; i < edgeCount; i++) {
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
}
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
cin >> u >> v;
graph[u].push_back(v);
cin >> u >> v;
graph[u][v] = 1;
graph[v][u] = 1;
cin >> u >> v;
graph[u][v] = 1;
會用 pair<int, int> 是因為有內建比較函式
typedef pair<int, int> Edge;
int main() {
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
vector< vector<Edge> > graph(vertexCount);
int u, v, w; // w is for weight
for (int i = 0; i < edgeCount; i++) {
cin >> u >> v >> w;
graph[u].push_back({w, v});
graph[v].push_back({w, u});
}
}
p.first 和 p.second 不好打?
用 priority_queue 會有問題,但很難寫
struct E {
int to;
int w;
};
int main() {
priority_queue<E, vector<E>, function<bool(E, E)> > pq(
[](const E& a, const E& b) {
return (a.w != b.w ? a.w < b.w : a.to < b.to);
}
);
}
項目 | 鄰接矩陣 | 鄰接串列 |
---|---|---|
空間複雜度 | ||
插入邊 | ||
查詢邊 | ||
枚舉邊 |
Other Methods
#include <iostream>
using namespace std;
int main() {
int height, length;
cin >> height >> length;
vector<string> graph(height);
for (auto& s: graph) cin >> s;
}
int main() {
int height, length;
cin >> height >> length;
vector<vector<int>> graph(height + 2,
vector<int>(length + 2, -1));
for (int i = 1; i <= height; i++) {
for (int j = 1; j <= length; j++) {
cin >> graph[i][j];
if (graph[i][j]) graph[i][j] = -1;
}
}
}
#include <bits/stdc++.h>
using namespace std;
int main() {
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
vector< pair<int, int> > edgeList(edgeCount);
for (auto& [u, v]: edgeList) {
cin >> u >> v;
}
}
Graph Traversal
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
我們現在有某個點突然有很多的水的一張圖,而我們現在想要計算出這張圖中的點何時會被水淹到,該怎麼做呢?
vector<int> bfs(int source, vector< vector<int> >& graph) {
queue<int> q;
q.push(source);
vector<int> distance(graph.size(), INT32_MAX);
distance[source] = 0;
while (!q.empty()) { // while (q.size())
int& current = q.front();
for (auto& n: graph[current]) {
if (distance[n] != INT32_MAX) continue;
distance[n] = distance[current] + 1;
q.push(n);
}
q.pop();
}
distance[source] = 0;
return distance;
}
四個方向的
while (!q.empty()) { // while (q.size())
auto& [x, y] = q.front();
// queue< pair<int, int> > q;
if (graph[x][y + 1] == INT32_MAX) {
graph[x][y + 1] = graph[x][y] + 1;
q.push({x, y + 1});
}
if (graph[x][y - 1] == INT32_MAX) {
graph[x][y - 1] = graph[x][y] + 1;
q.push({x, y - 1});
}
if (graph[x + 1][y] == INT32_MAX) {
graph[x + 1][y] = graph[x][y] + 1;
q.push({x + 1, y});
}
if (graph[x - 1][y] == INT32_MAX) {
graph[x - 1][y] = graph[x][y] + 1;
q.push({x - 1, y});
}
q.pop();
}
const int dx[] = {1,-1, 0, 0};
const int dy[] = {0, 0, 1,-1};
while (!q.empty()) {
auto& [x, y] = q.front();
for (int i = 0; i < 4; i++) {
auto& nextPosition = graph[x + dx[i]][y + dy[i]];
if (nextPosition == INT32_MAX) {
nextPosition = graph[x][y] + 1;
q.push({x + dx[i], y + dy[i]});
}
}
q.pop();
}
void dfs(int current, vector< vector<int> >& graph, vector<bool>& visited) {
visited[current] = 1;
for (auto& n: graph[current]) {
if (visited[n]) continue;
dfs(n, graph, visited);
}
}
int main() {
int vC, eC;
cin >> vC >> eC;
vector< vector<int> > graph(vC);
int u, v;
for (int i = 0; i < eC; i++) {
cin >> u >> v;
graph[u].push_back(v);
}
vector<bool> visited(vC);
dfs(0, graph, visited);
}
vector<bool> visited(vC);
function<void(int)> dfs = [&](int current) {
visited[current] = 1;
for (auto& n: graph[current]) {
if (!visited[n]) dfs(n);
}
};
vector< pair<int, int> > tree(vC);
int leftChild, rightChild;
for (int i = 0; i < vC; i++) {
cin >> leftChild >> rightChild;
tree[i] = {leftChild, rightChild};
}
vector<int> preorder, inorder, postorder;
function<void(int)> dfs = [&](int current) {
auto [l, r] = tree[current];
preorder.push_back(current);
if (l >= 0) dfs(l);
inorder.push_back(current);
if (r >= 0) dfs(r);
postorder.push_back(current);
};
Topological Sort
vector<int> topologicalSort(vector< vector<int> >& graph) {
vector<int> indegree(graph.size());
for (auto& v: graph) for (auto& n: v) indegree[n]++;
vector<int> order;
order.reserve(graph.size());
queue<int> q;
for (int i = 0; i < graph.size(); i++) {
if (indegree[i] == 0) q.push(i);
}
while (!q.empty()) {
auto& current = q.front();
order.push_back(current);
for (auto& n: graph[current]) {
if (--indegree[n] == 0) q.push(n);
}
}
return order;
}
vector<int> topologicalSort(vector< vector<int> >& graph) {
vector<int> order;
order.reserve(graph.size());
vector<int> visited(graph.size());
bool cyclic = false;
function<void(int, int&)> dfs = [&](int now, int& s) {
if (cyclic) return;
visited[now] = s;
for (auto& n: graph[now]) {
if (visited[n] == s) {
cyclic = true;
return;
}
if (!visited[n]) dfs(n, s);
}
order.push_back(now);
};
for (int i = 0; i < graph.size(); i++) dfs(i, i);
if (cyclic) return vector<int>(0);
reverse(order.begin(), order.end());
return order;
}
function<void(int, const int&)> dfs
= [&](int now, const int s) {
if (cyclic || visited[now]) return;
visited[now] = s;
for (auto& n: graph[now]) {
if (visited[n] == s) {
cyclic = true;
return;
}
if (!visited[n]) dfs(n, s);
}
order.push_back(now);
};
for (int i = 0; i < graph.size(); i++) dfs(i, i+1);
Disjoint Set
vector<int> master(vertexCount);
int query(int i) {
if (master[i] == i) return i;
return query(master[i]);
}
int query(int i) {
return (master[i] == i ? i : query(master[i]));
}
int query(int i) {
if (master[i] == i) return i;
master[i] = query(master[i]);
return master[i];
}
struct DisjointSet {
vector<int> master, depth;
disjointSet(int vertexCount) {
master.resize(vertexCount);
depth.resize(vertexCount);
for (int i = 0; i < vertexCount; i++) {
master[i] = i;
depth[i] = 1;
}
}
int query(int i) {
if (master[i] == i) return i;
return master[i] = query(master[i]);
}
void merge(int a, int b) {
a = query(a);
b = query(b);
if (a == b) return;
if (depth[a] < depth[b]) swap(a, b);
master[b] = a;
depth[a] += depth[b];
}
}; // 記得分號
Lowest Common Ancestor
我發現樹論會講,這裡先講其中一種作法就好了
vector< vector<int> > ancestor;
for (int j = 1; j <= __lg(maxDepth); j++) {
for (int i = 0; i < vertexCount; i++) {
ancestor[i][j] = ancestor[ancestor[i][j - 1]][j - 1];
}
}
vector<int> depth(vC);
function<void(int, int)> dfs = [&](int current, int d = 1) {
depth[current] = d++;
for (auto& n: graph[current]) {
if (depth[n]) continue;
dfs(n, d);
}
};
function<int(int, int)> lca = [&](int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
if (depth[u] != depth[v]) {
int dif = depth[u] - depth[v];
for (int i = 0; dif > 0; i++) {
if (dif & 1) u = ancestor[u][i];
dif >>= 1;
}
}
for (int i = __lg(maxDepth); i >= 0; i--) {
if (ancestor[u][i] != ancestor[v][i]) {
u = ancestor[u][i];
v = ancestor[v][i];
}
}
return ancestor[u][0];
};
#include <bits/stdc++.h>
using namespace std;
int main() {
int vertexCount, query;
cin >> vertexCount >> query;
vector< vector<int> > graph(vertexCount);
int a, b;
for (int i = 1; i < vertexCount; i++) {
cin >> a >> b;
graph[a].push_back(b);
graph[b].push_back(a);
}
vector< vector<int> > ancestor(vertexCount, vector<int>(1));
vector<int> depth(vertexCount);
function<void(int, int)> dfs = [&](int current, int d) {
depth[current] = d++;
for (auto& n: graph[current]) {
if (depth[n]) continue;
ancestor[n][0] = current;
dfs(n, d);
}
};
dfs(0, 1);
int maxDepth = 0;
for (auto& n: depth) maxDepth = max(maxDepth, n);
for (auto& v: ancestor) v.resize(__lg(maxDepth) + 1);
for (int j = 1; j <= __lg(maxDepth); j++) {
for (int i = 0; i < vertexCount; i++) {
ancestor[i][j] = ancestor[ancestor[i][j - 1]][j - 1];
}
}
function<int(int, int)> lca = [&](int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
if (depth[u] != depth[v]) {
int dif = depth[u] - depth[v];
for (int i = 0; dif > 0; i++) {
if (dif & 1) u = ancestor[u][i];
dif >>= 1;
}
}
if (u == v) return u;
for (int i = __lg(maxDepth); i >= 0; i--) {
if (ancestor[u][i] != ancestor[v][i]) {
u = ancestor[u][i];
v = ancestor[v][i];
}
}
return ancestor[u][0];
};
while (query--) {
cin >> a >> b;
cout << lca(a, b) << '\n';
}
}
Spanning Tree
typedef pair<int, int> pii;
typedef pair<int, pii> pi_ii;
struct DisjointSet {
vector<int> master;
DisjointSet(int vertexCount) {
master.resize(vertexCount);
iota(master.begin(), master.end(), 0);
}
int query(int a) {
if (a == master[a]) return a;
return master[a] = query(master[a]);
}
bool connected(int a, int b) {
return query(a) == query(b);
}
void merge(int a, int b) {
master[query(a)] = master[b];
}
};
int kruskal(vector<pi_ii>& minEdge, DisjointSet& ds) {
int cost = 0;
for (auto& [w, uv]: minEdge) {
auto& [u, v] = uv;
if (ds.connected(u, v)) continue;
ds.merge(u, v);
cost += w;
}
return cost;
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
DisjointSet ds(vertexCount);
vector<pi_ii> minEdge(edgeCount);
for (auto& [w, uv]: minEdge) {
auto& [u, v] = uv;
cin >> u >> v >> w;
}
sort(minEdge.begin(), minEdge.end());
cout << kruskal(minEdge, ds) << '\n';
}
typedef pair<int, int> pii;
int prim(vector< vector<pii> >& graph) {
priority_queue<pii, vector<pii>, greater<pii> > pq;
vector<int> currentMinCost(graph.size(), INT32_MAX);
vector<bool> inside(graph.size(), false);
int sum = 0;
pq.push({0, 0});
currentMinCost[0] = 0;
while (!pq.empty()) {
auto [w, u] = pq.top();
pq.pop();
if (inside[u]) continue;
inside[u] = true;
sum += w;
for (auto& [w, v]: graph[u]) {
if (!inside[v] && currentMinCost[v] > w) {
currentMinCost[v] = w;
pq.push({w, v});
}
}
}
return sum;
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int vertexCount, edgeCount;
cin >> vertexCount >> edgeCount;
vector< vector<pii> > graph(vertexCount);
int u, v, w;
for (int i = 0; i < edgeCount; i++) {
cin >> u >> v >> w;
graph[u].push_back({w, v});
graph[v].push_back({w, u});
}
cout << prim(graph) << '\n';
}
Shortest Path
vector< vector<int> > d(vC, vector<int>(vC, 1e9 + 225));
for (int i = 0; i < vC; i++) d[i][i] = 0;
int u, v, w;
for (int i = 0; i < eC; i++) {
cin >> u >> v >> w;
d[u][v] = min(d[u][v], w);
}
for (int k = 0; k < vC; k++) {
for (int i = 0; i < vC; i++) {
for (int j = 0; j < vC; j++) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
struct Edge {
int u, v, w;
};
vector<int> Bellman_Ford(int vertexCount, int source, vector<Edge>& edge) {
vector<int> distance(vertexCount, INT32_MAX);
distance[source] = 0;
for (int i = 1; i < vertexCount; i++) {
for (auto& [u, v, w]: edge) {
distance[u] = min(distance[u], distance[v] + w);
distance[v] = min(distance[v], distance[u] + w);
}
}
return distance;
}
typedef pair<int, int> pii;
vector<int> SPFA(vector< vector<pii>& graph, int source) {
vector<int> distance(graph.size(), INT32_MAX);
distance[source] = 0;
queue<int> q;
vector<bool> inQueue(graph.size(), 0);
q.push(source);
while (!q.empty()) {
auto v = q.front();
q.pop();
inQueue[v] = 0;
for (auto& [u, w]: graph[v]) {
distance[u] = min(distance[u], distance[v] + w);
if (inQueue[u]) continue;
q.push(u);
inQueue[u] = 1;
}
}
return distance;
}
typedef pair<int, int> pii;
vector<int> Dijkstra(vector< vector<pii> >& graph, int source) {
vector<int> distance(graph.size(), INT32_MAX);
distance[source] = 0;
vector<bool> visited(graph.size(), 0);
priority_queue<pii, vector<pii>, greater<pii> > pq;
pq.push({0, source});
while (!pq.empty()) {
auto [w, u] = pq.top();
pq.pop();
if (visited[u]) continue;
visited[u] = 1;
for (auto& [w, v]: graph[u]) {
if (distance[v] <= distance[u] + w) continue;
distance[v] = distance[u] + w;
pq.push({distance[v], v});
}
}
return distance;
}
Connectivity
vector<int> low(vC);
vector<int> preorder(vC);
vector<bool> isCutVertex(vC);
int counter = 0;
function<void(int, int)> dfs = [&](int u, int last) {
low[u] = preorder[u] = ++counter;
int child = 0;
for (auto& v: graph[u]) {
if (v == last) continue;
if (preorder[v]) { // is back edge
low[u] = min(low[u], preorder[v]);
} else {
dfs(v, u);
if (last >= 0 && low[v] >= preorder[u]) {
isCutVertex[u] = true;
}
child++;
low[u] = min(low[u], low[v]);
}
}
if (last < 0 && child > 1) isCutVertex[u] = true;
};
dfs(0, -1);
vector<int> low(vC);
vector<int> order(vC);
set<pii> isBridge;
int counter = 0;
function<void(int, int)> dfs = [&](int current, int last) {
low[current] = order[current] = ++counter;
for (auto& v: graph[current]) {
if (v == last) continue;
if (order[v]) { // is back edge
low[current] = min(low[current], order[v]);
// a back edge always forms a cycle
} else {
dfs(v, current);
low[current] = min(low[current], low[v]);
if (low[v] > order[current]) {
isBridge.insert({current, v});
}
}
}
};
dfs(0, -1);
Components
struct Edge {
int a, b;
Edge(int u = -1, int v = -1): a(u), b(v) {}
};
vector< vector<int> > graph;
vector<int> low, preorder;
vector<int> isCutVertex;
stack<Edge> s;
vector<int> bccId;
vector< vector<int> > bcc;
int counter = 0;
int bccCounter = 0;
void dfs(int u, int p) {
low[u] = preorder[u] = ++counter;
int child = 0;
for (auto& v: graph[u]) {
Edge e(u, v);
if (v == p) continue;
s.push(e);
if (preorder[v]) {
low[u] = min(low[u], preorder[v]);
continue;
}
child++;
dfs(v, u);
low[u] = min(low[u], low[v]);
if (low[v] >= preorder[u]) {
isCutVertex[u] = 1;
++bccCounter;
Edge temp;
do {
temp = s.top(), s.pop();
if (bccId[temp.a] != bccCounter) bcc[bccCounter].push_back(temp.a);
if (bccId[temp.b] != bccCounter) bcc[bccCounter].push_back(temp.b);
bccId[temp.a] = bccId[temp.b] = bccCounter;
} while (temp.a != u || temp.b != v);
}
}
if (p <= 0 && child == 1) {
isCutVertex[u] = 0;
}
}
vector< vector<int> > graph;
vector<int> low, preorder;
stack<int> s;
vector<int> bccId;
vector< vector<int> > bcc;
int counter = 0;
int bccCounter = 0;
void dfs(int u, int p) {
low[u] = preorder[u] = ++counter;
s.push(u);
for (auto& v: graph[u]) {
if (v == p) continue;
if (preorder[v]) {
low[u] = min(low[u], preorder[v]);
continue;
}
dfs(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > preorder[u]) {
++bccCounter;
int w;
do {
w = s.top(), s.pop();
bccId[w] = bccCounter;
} while (w != u);
}
}
if (p < 0) {
++bccCounter;
int w;
while (!s.empty()) {
w = s.top(), s.pop();
bccId[w] = bccCounter;
}
}
}
#include <bits/stdc++.h>
using namespace std;
vector<int> tarjan(vector< vector<int> >& graph) {
vector<int> preorder(graph.size());
vector<int> low(graph.size());
vector<int> scc(graph.size());
stack<int> s;
int counter = 0;
int sccId = 0;
function<void(int)> dfs = [&](int u) {
preorder[u] = low[u] = ++counter;
s.push(u);
for (auto& v: graph[u]) {
if (scc[v]) continue;
if (preorder[v]) low[u] = min(low[u], preorder[v]);
if (!preorder[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
}
}
if (low[u] == preorder[u]) {
++sccId;
int v;
do {
v = s.top(), s.pop();
scc[v] = sccId;
} while (u != v);
}
};
for (int i = 0; i < graph.size(); i++) if (!preorder[i]) dfs(i);
return scc;
}
void dfs(int current, vector<int>& postorder, vector<bool>& visited, vector< vector<int> >& graph) {
visited[current] = 1;
for (auto& v: graph[current]) {
if (visited[v]) continue;
dfs(v, postorder, visited, graph);
}
postorder.push_back(current);
}
void sfd(int current, vector<int>& scc, const int id, vector< vector<int> >& hparg) {
scc[current] = id;
for (auto& v: hparg[current]) {
if (scc[v]) continue;
sfd(v, scc, id, hparg);
}
}
vector<int> kosaraju(vector< vector<int> >& graph) {
vector<bool> visited(graph.size());
vector<int> postorder;
postorder.reserve(graph.size());
function<void(int)> dfs = [&](int u) {
if (visited[u]) return;
for (auto& v: graph[u]) {
visited[v] = true;
dfs(v);
}
postorder.push_back(u);
};
for (int u = 0; u < graph.size(); u++) dfs(u);
vector< vector<int> > hparg(graph.size());
for (int u = 0; u < graph.size(); u++) {
for (auto& v: graph[u]) hparg[v].push_back(u);
}
vector<int> scc(graph.size());
int sccCounter = 0;
function<void(int)> sfd = [&](int u) {
scc[u] = sccCounter;
for (auto& v: hparg[u]) {
if (scc[v]) continue;
sfd(v);
}
};
reverse(postorder.begin(), postorder.end());
for (auto& u: postorder) {
if (!scc[u]) ++sccCounter, sfd(u);
}
return scc;
}
Thank you