1 双向邻接表
inline void addedge(int u, int v) {
to[++E] = v, next[E] = first[u], first[u] = E;
to[++E] = u, next[E] = first[v], first[v] = E;
}
2 有向图的强连通分量
void dfs(int x) {
int i, y;
id[x] = low[x] = ++cnt; instack[x] = 1; sta[stc++] = x;
for(i = first[x]; i; i = next[i])
if (!id[y = to[i]])
dfs(y), down(low[x], low[y]);
else if (instack[y])
down(low[x], id[y]);
if (id[x] == low[x])
for (y = 0; y != x; )
y = sta[--stc], instack[y] = 0, top[y] = x;
}
3 有向无环图的拓扑排序
void Toposort(){
int h, t = 0, x, y, i;
for (i = 1; i <= V; ++i) if (!deg[i]) que[t++] = i;
for (h = 0; h < t; ++h)
for (i = first[x = que[h]]; i; i = next[i])
if (!--deg[y = to[i]]) que[t++] = y;
}
4 无向图的桥边
void dfs(int x, int px = 0) {
int i, y;
id[x] = low[x] = ++cnt;
for (i = first[x]; i; i = next[i])
if (!id[y = to[i]]){
dfs(y, i), down(low[x], low[y]);
if (id[x] < low[y]) // edge i is a bridge
} else if (px - 1 ^ i - 1 ^ 1)
down(low[x], id[y]);
}
5 无向图的割点
void dfs(int x, int px = 0) {
int i, y, c = 0; bool is_cut;
id[x] = low[x] = ++cnt;
for (i = first[x]; i; i = next[i])
if (!id[y = to[i]]) {
dfs(y, i), down(low[x], low[y]), ++c;
if (id[x] <= low[y]) is_cut = true;
} else if (px - 1 ^ i - 1 ^ 1)
down(low[x], id[y]);
is_cut |= !px && c > 1;
}
6 无向图的边双缩点
void dfs(int x, int px = 0) {
int i, y;
id[x] = low[x] = ++cnt, stack[stc++] = x;
for (i = first[x]; i; i = next[i])
if (!id[y = to[i]]) {
dfs(y, i), down(low[x], low[y]);
if (id[x] < low[y]) bridge[ad(i)] = bridge[i] = true;
} else if (px - 1 ^ i - 1 ^ 1)
down(low[x], id[y]);
if (id[x] == low[x])
for (y = 0; y != x; )
y = stack[--stc], top[y] = x;
}
7 无向图的点双缩点 / 圆方树
void dfs(int x, int px = 0) {
int i, y, z;
id[x] = low[x] = ++cnt, stack[top++] = x;
for (i = first[x]; i; i = next[i])
if (!id[y = to[i]]) {
dfs(y, i), down(low[x], low[y]);
if (id[x] <= low[y])
for (link(++bcc_cnt + V, x), z = 0; z != y; )
link(z = stack[--top], bcc_cnt + V);
} else if (px - 1 ^ i - 1 ^ 1)
down(low[x], id[y]);
}
8 带权 edge 结构体
struct edge {
int u, v, w;
edge (int u0 = 0, int v0 = 0, int w0 = 0) : u(u0), v(v0), w(w0) {}
};
9 单源最短路 (Dijkstra)
#include <ext/pb_ds/priority_queue.hpp>
using __gnu_pbds::priority_queue;
struct node{
int to, dist;
node (int to0 = 0, int dist0 = 0): to(to0), dist(dist0) {}
inline bool operator < (const node &b) const {return dist > b.dist;}
};
priority_queue <node> pq;
void Dijkstra(int s){
int i, y; node t;
for(i = 1; i <= V; i++) d[i] = (i == s ? 0 : INF);
for(pq.push(node(s, 0)); !pq.empty(); ){
t = pq.top(); pq.pop();
if(d[t.to] < t.dist) continue;
for(i = first[t.to]; i; i = next[i])
if(t.dist + e[i].w < d[y = e[i].v]){
d[y] = t.dist + e[i].w;
pq.push(node(y, d[y]));
}
}
}
10 所有点对的最短路 (Floyd)
int Floyd(){
int i, j, k;
for(k = 1; k <= V; k++)
for(i = 1; i <= V; i++)
for(j = 1; j <= V; j++)
down(d[i][j], d[i][k] + d[k][j]);
return 0;
}
11 最小生成树 (Kruskal)
struct edge{
int u, v, w;
edge (int u0 = 0, int v0 = 0, int w0 = 0): u(u0), v(v0), w(w0) {}
bool operator < (const edge &b) const {return w < b.w;}
};
void Kruskal(){
uf.resize(V);
sort(e + 1, e + (E + 1));
for(i = 1; i <= E; i++)
if(!uf.test(e[i].u, e[i].v, true)){
// e is an edge of minimum spanning tree
if(++Es >= V - 1) return;
}
}
12 网络流 edge 结构体
struct edge{
int u, v, f; // f is remaining flow
edge(int u0 = 0, int v0 = 0, int f0 = 0): u(u0), v(v0), f(f0) {}
};
13 最大流 (Dinic)
namespace Flow {
#define ad(x) ((x - 1 ^ 1) + 1)
const int N = 2000, M = 100000;
struct edge {
int u, v, f;
edge (int u0 = 0, int v0 = 0, int f0 = 0) : u(u0), v(v0), f(f0) {}
} e[M];
int V = 2, E = 0, si = 1, ti = 2, flow;
int first[N], next[M];
int dep[N], cur[N], que[N];
inline void addedge(int u, int v, int f) {
e[++E] = edge(u, v, f), next[E] = first[u], first[u] = E;
e[++E] = edge(v, u), next[E] = first[v], first[v] = E;
}
bool bfs() {
int h, t = 1, i, x, y;
memset(dep, -1, sizeof dep);
que[0] = si, dep[si] = 0;
for (h = 0; h < t; h++) {
if ((x = que[h]) == ti) return true;
for (i = first[x]; i; i = next[i])
if (dep[y = e[i].v] == -1 && e[i].f)
que[t++] = y, dep[y] = dep[x] + 1;
}
return false;
}
int dfs(int x, int lim) {
int a, c, f = 0;
if (x == ti || !lim) return lim;
for (int &i = cur[x]; i; i = next[i])
if (dep[e[i].v] == dep[x] + 1 && e[i].f) {
a = std::min(lim - f, e[i].f);
c = dfs(e[i].v, a);
e[i].f -= c; e[ad(i)].f += c;
if ((f += c) == lim) return f;
}
return f;
}
int Dinic() {
for (flow = 0; bfs(); flow += dfs(si, INT_MAX))
memcpy(cur, first, sizeof cur);
return flow;
}
}
14 最小费用最大流 (Dinic)
namespace CF {
#define ad(x) ((x - 1 ^ 1) + 1)
const int N = 2000, M = 100000, INF = 0x7f7f7f7f;
struct edge {
int u, v, c, f;
edge (int u0 = 0, int v0 = 0, int c0 = 0, int f0 = 0) : u(u0), v(v0), c(c0), f(f0) {}
} e[M];
int V = 2, E = 0, si = 1, ti = 2, flow, cost;
int first[N], next[M];
int dep[N], cur[N], que[M << 1];
bool in_que[N], used[N];
inline void addedge(int u, int v, int c, int f) {
e[++E] = edge(u, v, c, f), next[E] = first[u], first[u] = E;
e[++E] = edge(v, u, -c), next[E] = first[v], first[v] = E;
}
bool bfs() {
int h = M, t = h + 1, i, x, y;
memset(dep, 127, sizeof dep);
que[h] = ti, dep[ti] = 0, in_que[ti] = true;
for (; h < t; ) {
x = que[h++], in_que[x] = false;
for (i = first[x]; i; i = next[i])
if (dep[y = e[i].v] > dep[x] - e[i].c && e[ad(i)].f) {
dep[y] = dep[x] - e[i].c;
if (!in_que[y])
in_que[y] = true, (dep[y] >= dep[que[h]] ? que[t++] : que[--h]) = y;
}
}
return dep[si] < INF;
}
int dfs(int x, int lim) {
int a, c, f = 0;
if (x == ti || !lim) return lim;
used[x] = true;
for (int &i = cur[x]; i; i = next[i])
if (dep[e[i].v] == dep[x] - e[i].c && e[i].f && !used[e[i].v]) {
a = std::min(lim - f, e[i].f);
c = dfs(e[i].v, a);
e[i].f -= c, e[ad(i)].f += c;
if ((f += c) == lim) return f;
}
return f;
}
int Dinic() {
int f;
for (cost = flow = 0; bfs(); ) {
memcpy(cur, first, sizeof cur);
memset(used, 0, sizeof used);
flow += f = dfs(si, INF);
cost += dep[si] * f;
}
return cost;
}
}
15 二分图最大匹配 (增广路算法)
bool dfs(int x){
for(int i = 1; i <= n_g; i++)
if(e[x][i] && !used[i]){
used[i] = 1;
if(!boy[i] || dfs(boy[i])){
boy[i] = x; girl[x] = i; return true;
}
}
return false;
}
16 一般图最大匹配 (带花树算法)
#define unknown -1
#define boy 0
#define girl 1
int LCA(int x, int y) {
for (++hash_cnt; x; y ? swap(x, y) : (void)0) {
x = ancestor(x);
if (hash[x] == hash_cnt) return x; // visited
hash[x] = hash_cnt;
x = prev[match[x]];
}
return 0x131a371;
}
void blossom(int x, int y, int root, int &t) { // vertices in blossoms are all boys !
for (int z; ancestor(x) != root; y = z, x = prev[y]) {
prev[x] = y; z = match[x];
if (col[z] == girl) que[t++] = z, col[z] = boy;
if (ancestor(x) == x) p[x] = root;
if (ancestor(z) == z) p[z] = root;
}
}
bool bfs(int st) {
int h, t = 1, i, x, y, b, g;
que[0] = st; col[st] = boy;
for (h = 0; h < t; ++h)
for (i = first[x = que[h]]; i; i = next[i])
if (col[y = to[i]] == unknown) { // common step
prev[y] = x; col[y] = girl;
if (!match[y]) { // augment (change mates) !!!
for (g = y; g; swap(match[b], g))
match[g] = b = prev[g];
return true;
}
col[que[t++] = match[y]] = boy;
} else if(col[y] == boy && ancestor(x) != ancestor(y)) { // flower !!!
b = LCA(x, y); blossom(x, y, b, t); blossom(y, x, b, t);
}
return false;
}
// main process
for (i = 1; i <= V; ++i) {
for (v = 1; v <= V; ++v) col[v] = unknown, p[v] = v;
if (!match[i] && bfs(i)) ++ans;
}