圖論
儲存
class C_Graph
{
public:
struct Edge
{
int u, v, w;
Edge(int _u = 0, int _v = 0, int _w = 0)
{
u = _u, v = _v, w = _w;
}
friend bool operator<(const Edge& a, const Edge& b)
{
return a.w < b.w;
}
int operator()(int x)const
{
return u ^ v ^ x;
}
};
/*====================*/
int n;
vector<Edge>edges;
vector<vector<int>>edge;
/*====================*/
void Init(int n)
{
this->n = n; edge.assign(n + 1, vector<int>());
}
void AddEdge(int u, int v, int w = 0)
{
edges.push_back(Edge(u, v, w));
edge[u].push_back(edges.size() - 1);
}
};
2-SAT
namespace _TwoSAT
{
using namespace _SCC;
void Init(void)
{
for (int i = 1; i <= n; ++i)
{
int u = idx[i][1], v = idx[i][0];
if (belong[u] == belong[v])
{
cout << "IMPOSSIBLE" << endl; return;
}
}
cout << "POSSIBLE" << endl;
for (int i = 1; i <= n; ++i)
{
int u = idx[i][1], v = idx[i][0];
cout << ((belong[u] < belong[v]) ? 1 : 0) << " ";
}
cout << endl;
}
}
尤拉圖
無向圖
namespace _Euler
{
/*
預設連通圖,-1不存在,0存在尤拉路徑,1存在尤拉回路
*/
const int N = 1e5 + 10;
/*====================*/
int degree[N];
/*====================*/
int Init(void)
{
for (int i = 1; i <= n; ++i)
{
degree[i] = G[i].size();
}
int cnt = 0;
for (int i = 1; i <= n; ++i)
{
if (degree[i] % 2 == 1)cnt++;
}
return cnt == 0 ? 1 : (cnt == 2 ? 0 : -1);
}
}
有向圖
namespace _Euler
{
/*
預設連通圖,-1不存在,0存在尤拉路徑,1存在尤拉回路
*/
const int N = 1e5 + 10;
/*====================*/
int degree[N];
/*====================*/
int Init(void)
{
for (int i = 1; i <= n; ++i)
{
degree[i] = 0;
}
for (int i = 1; i <= m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
degree[u]++, degree[v]--;
}
int cnt1 = 0, cnt2 = 0, cnt3 = 0;
for (int i = 1; i <= n; ++i)
{
if (degree[i] == -1)cnt1++;
if (degree[i] == +0)cnt2++;
if (degree[i] == +1)cnt3++;
}
if (cnt1 == 1 && cnt3 == 1 && cnt2 + 2 == n)
{
return +0;
}
else if (cnt2 == n)
{
return +1;
}
else
{
return -1;
}
}
}
最大團
namespace _MaxClique
{
const int N = 5e1 + 10;
/*====================*/
int n; int G[N][N];
int dp[N], stk[N][N], res;
/*====================*/
bool DFS(int ns, int dep)
{
if (ns == 0)
{
if (dep > res)
{
res = dep; return true;
}
return false;
}
for (int i = 0; i < ns; ++i)
{
int u = stk[dep][i], cnt = 0;
if (dep + dp[u] <= res)return false;
if (dep + ns - i <= res)return false;
for (int j = i + 1; j < ns; ++j)
{
int v = stk[dep][j];
if (G[u][v])stk[dep + 1][cnt++] = v;
}
if (DFS(cnt, dep + 1))return true;
}
return false;
}
/*====================*/
int Init(void)
{
cin >> n; res = 0;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
cin >> G[i][j];
}
}
for (int i = n; i >= 1; --i)
{
int ns = 0;
for (int j = i + 1; j <= n; ++j)
{
if (G[i][j])stk[1][ns++] = j;
}
DFS(ns, 1); dp[i] = res;
}
return res;
}
}
最短路
單源最短路SSSP
SPFA
vector<int> SPFA(C_Graph& G, int s)
{
vector<int>dis(G.n + 1, INF);
vector<bool>vis(G.n + 1, false);
queue<int>q; dis[s] = 0; q.push(s);
while (!q.empty())
{
int cur = q.front(); q.pop(); vis[cur] = false;
for (auto idx : G.edge[cur])
{
int val = G.edges[idx].w;
int nxt = G.edges[idx](cur);
if (dis[nxt] > dis[cur] + val)
{
dis[nxt] = dis[cur] + val;
if (!vis[nxt])q.push(nxt), vis[nxt] = true;
}
}
}
return dis;
}
Dijkstra
class C_Dijkstra
{
public:
struct Unit
{
int v, w;
Unit(int _v = 0, int _w = 0)
{
v = _v, w = _w;
}
friend bool operator<(const Unit& a, const Unit& b)
{
return a.w > b.w;
}
};
vector<int> operator()(C_Graph& G, int s)
{
vector<int>dis(G.n + 1, INF);
vector<bool>vis(G.n + 1, false);
priority_queue<Unit>q; q.push(Unit(s, dis[s] = 0));
while (!q.empty())
{
int cur = q.top().v; q.pop();
if (vis[cur])continue; vis[cur] = true;
for (auto idx : G.edge[cur])
{
int val = G.edges[idx].w;
int nxt = G.edges[idx](cur);
if (dis[nxt] > dis[cur] + val)
{
dis[nxt] = dis[cur] + val;
q.push(Unit(nxt, dis[nxt]));
}
}
}
return dis;
}
};
SPFA-SLF
vector<int> SPFA(C_Graph& G, int s)
{
vector<int>dis(G.n + 1, INF);
vector<bool>vis(G.n + 1, false);
deque<int>q; dis[s] = 0; q.push_back(s);
while (!q.empty())
{
int cur = q.front(); q.pop_front(); vis[cur] = false;
if (!q.empty() && dis[q.front()] > dis[q.back()])
{
swap(q.front(), q.back());
}
for (auto idx : G.edge[cur])
{
int val = G.edges[idx].w;
int nxt = G.edges[idx](cur);
if (dis[nxt] > dis[cur] + val)
{
dis[nxt] = dis[cur] + val;
if (!vis[nxt])
{
vis[nxt] = true;
if (!q.empty() && dis[nxt] < dis[q.front()])
{
q.push_front(nxt);
}
else
{
q.push_back(nxt);
}
}
}
}
}
return dis;
}
全源最短路APSP
Floyd
vector<vector<int>> Floyd(C_Graph& G)
{
vector<vector<int>>dis(G.n + 1, vector<int>(G.n + 1, INF));
for (int u = 1; u <= G.n; ++u)
{
dis[u][u] = 0;
for (auto idx : G.edge[u])
{
int v = G.edges[idx](u);
int w = G.edges[idx].w;
dis[u][v] = min(dis[u][v], w);
}
}
for (int k = 1; k <= G.n; ++k)
{
for (int i = 1; i <= G.n; ++i)
{
for (int j = 1; j <= G.n; ++j)
{
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
return dis;
}
Johnson
環相關
有向圖判環
bool Loop(C_Graph& G)
{
queue<int>q; int cnt = 0;
vector<int>indegree(G.n + 1, 0);
for (int i = 0; i < G.edges.size(); ++i)
{
indegree[G.edges[i].v]++;
}
for (int i = 1; i <= G.n; ++i)
{
if (indegree[i] == 0)q.push(i);
}
while (!q.empty())
{
int cur = q.front(); q.pop(); cnt++;
for (auto idx : G.edge[cur])
{
int nxt = G.edges[idx](cur);
if (--indegree[nxt] == 0)q.push(nxt);
}
}
return cnt != G.n;
}
任意圖判負環
bool Loop(C_Graph& G)
{
vector<int>cnt(G.n + 1, 0);
vector<int>dis(G.n + 1, 0);
vector<bool>vis(G.n + 1, false);
/*====================*/
queue<int>q;
for (int i = 1; i <= G.n; ++i)
{
q.push(i); vis[i] = true;
}
while (!q.empty())
{
int cur = q.front(); q.pop(); vis[cur] = false;
for (auto idx : G.edge[cur])
{
int val = G.edges[idx].w;
int nxt = G.edges[idx](cur);
if (dis[nxt] > dis[cur] + val)
{
cnt[nxt] = cnt[cur] + 1;
dis[nxt] = dis[cur] + val;
if (cnt[nxt] >= G.n)return true;
if (!vis[nxt])q.push(nxt), vis[nxt] = true;
}
}
}
return false;
}
無向圖求最小環
int Loop(C_Graph& G)
{
vector<vector<int>>mindis(G.n + 1, vector<int>(G.n + 1, INF));
for (int u = 1; u <= G.n; ++u)
{
mindis[u][u] = 0;
for (auto idx : G.edge[u])
{
int v = G.edges[idx](u);
int w = G.edges[idx].w;
mindis[u][v] = min(mindis[u][v], w);
}
}
auto dis = mindis; int res = INF;
for (int k = 1; k <= G.n; ++k)
{
for (int i = 1; i < k; ++i)
{
for (int j = i + 1; j < k; ++j)
{
if (mindis[i][j] != INF)
{
res = min(res, mindis[i][j] + dis[i][k] + dis[k][j]);
}
}
}
for (int i = 1; i <= G.n; ++i)
{
for (int j = 1; j <= G.n; ++j)
{
mindis[i][j] = min(mindis[i][j], mindis[i][k] + mindis[k][j]);
}
}
}
return res;
}
有向圖求最小環
int Loop(C_Graph& G)
{
vector<vector<int>>inedge(G.n + 1, vector<int>());
for (int i = 0; i < G.edges.size(); ++i)
{
inedge[G.edges[i].v].push_back(i);
}
int res = INF;
for (int v = 1; v <= G.n; ++v)
{
vector<int>dis = Dijkstra(G, v);
for (auto idx : inedge[v])
{
res = min(res, dis[G.edges[idx](v)] + G.edges[idx].w);
}
}
return res;
}
無向圖三元環計數
int Loop(C_Graph& G)
{
vector<int>tag(G.n + 1, 0);
vector<int>degree(G.n + 1, 0);
vector<vector<int>>out(G.n + 1, vector<int>());
for (auto& e : G.edges)
{
degree[e.u]++, degree[e.v]++;
}
for (auto& e : G.edges)
{
int u = e.u, v = e.v;
if (degree[u] == degree[v] && u > v)swap(u, v);
if (degree[u] != degree[v] && degree[u] > degree[v])swap(u, v);
out[u].push_back(v);
}
int res = 0;
for (int u = 1; u <= G.n; ++u)
{
for (auto v : out[u])
{
tag[v] = u;
}
for (auto v : out[u])
{
for (auto w : out[v])
{
res += (tag[w] == u);
}
}
}
return res;
}
網路流
最大流
ISAP
namespace _ISAP
{
const int N = 1e5 + 10;
const int M = 1e5 + 10;
/*====================*/
const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int u, v, c, f;
Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
{
u = _u, v = _v, c = _c, f = _f;
}
};
/*====================*/
int pre[N];//路徑前驅
int cur[N];//當前弧最佳化
int n, m, s, t;//點,邊,源,匯
vector<int>G[N];//鄰接表
int d[N], vis[N], num[N];//圖分層
Edge edge[2 * M]; int cnt;//邊
/*====================*/
void AddEdge(int u, int v, int c)
{
edge[cnt++] = Edge(u, v, c, 0);
edge[cnt++] = Edge(v, u, 0, 0);
G[u].push_back(cnt - 2);
G[v].push_back(cnt - 1);
}
/*====================*/
void BFS(void)
{
for (int i = 0; i <= n; ++i)
{
d[i] = vis[i] = num[i] = 0;
}
queue<int>q; q.push(t);
d[t] = 0; vis[t] = 1;
while (!q.empty())
{
int x = q.front(); q.pop();
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (!vis[e.u] && e.c > e.f)
{
vis[e.u] = 1; d[e.u] = d[x] + 1; q.push(e.u);
}
}
}
for (int i = 0; i < n; ++i)num[d[i]]++;
}
int Augumemt(void)
{
int x, k = INF;
x = t; while (x != s)
{
Edge& e = edge[pre[x]];
k = min(k, e.c - e.f);
x = edge[pre[x]].u;
}
x = t; while (x != s)
{
edge[pre[x]].f += k;
edge[pre[x] ^ 1].f -= k;
x = edge[pre[x]].u;
}
return k;
}
int MaxFlow(void)
{
for (int i = 1; i <= n; ++i)
{
pre[i] = cur[i] = 0;
}
BFS(); int x = s, flow = 0;
while (d[s] < n)
{
if (x == t)
{
flow += Augumemt(); x = s;
}
int flag = 0;
for (int& i = cur[x]; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (e.c > e.f && d[x] == d[e.v] + 1)
{
flag = 1; pre[e.v] = G[x][i]; x = e.v; break;
}
}
if (!flag)
{
int l = n - 1;
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (e.c > e.f)l = min(l, d[e.v]);
}
if (--num[d[x]] == 0)break;
num[d[x] = l + 1]++; cur[x] = 0;
if (x != s)x = edge[pre[x]].u;
}
}
return flow;
}
/*====================*/
int Init(void)
{
cnt = 0;
cin >> n >> m >> s >> t;
for (int i = 1; i <= n; ++i)
{
G[i].clear();
}
for (int i = 1; i <= m; ++i)
{
int u, v, c;
cin >> u >> v >> c;
AddEdge(u, v, c);
}
return MaxFlow();
}
};
HLPP
namespace _HLPP
{
const int N = 1e5 + 10;
const int M = 1e5 + 10;
/*====================*/
const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int next, v, c;
Edge(int _next = 0, int _v = 0, int _c = 0)
{
next = _next, v = _v, c = _c;
}
};
/*====================*/
int n, m, s, t;
int d[N], num[N];
stack<int> lib[N];
int ex[N], level = 0;
Edge edge[2 * M]; int head[N], cnt;
/*====================*/
void AddEdge(int u, int v, int c)
{
edge[cnt] = Edge(head[u], v, c), head[u] = cnt++;
edge[cnt] = Edge(head[v], u, 0), head[v] = cnt++;
}
/*====================*/
int Push(int u)
{
bool init = u == s;
for (int i = head[u]; i != -1; i = edge[i].next)
{
const int& v = edge[i].v, & c = edge[i].c;
if (!c || init == false && d[u] != d[v] + 1)continue;
int k = init ? c : min(c, ex[u]);
if (v != s && v != t && !ex[v]) lib[d[v]].push(v), level = max(level, d[v]);
ex[u] -= k, ex[v] += k, edge[i].c -= k, edge[i ^ 1].c += k;
if (!ex[u]) return 0;
}
return 1;
}
void Relabel(int x)
{
d[x] = INF;
for (int i = head[x]; i != -1; i = edge[i].next)
{
if (edge[i].c) d[x] = min(d[x], d[edge[i].v]);
}
if (++d[x] < n)
{
lib[d[x]].push(x); level = max(level, d[x]); ++num[d[x]];
}
}
bool BFS(void)
{
for (int i = 1; i <= n; ++i)
{
d[i] = INF; num[i] = 0;
}
queue<int>q; q.push(t), d[t] = 0;
while (!q.empty())
{
int u = q.front(); q.pop(); num[d[u]]++;
for (int i = head[u]; i!=-1; i = edge[i].next)
{
const int& v = edge[i].v;
if (edge[i ^ 1].c && d[v] > d[u] + 1) d[v] = d[u] + 1, q.push(v);
}
}
return d[s] != INF;
}
int Select(void)
{
while (lib[level].size() == 0 && level > -1) level--;
return level == -1 ? 0 : lib[level].top();
}
int MaxFlow(void)
{
if (!BFS()) return 0;
d[s] = n; Push(s); int x;
while (x = Select())
{
lib[level].pop();
if (Push(x))
{
if (!--num[d[x]])
{
for (int i = 1; i <= n; ++i)
{
if (i != s && i != t && d[i] > d[x] && d[i] < n + 1)
{
d[i] = n + 1;
}
}
}
Relabel(x);
}
}
return ex[t];
}
/*====================*/
int Init(void)
{
cnt = 0;
cin >> n >> m >> s >> t;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; ++i)
{
int u, v, c;
cin >> u >> v >> c;
AddEdge(u, v, c);
}
return MaxFlow();
}
}
Dinic
/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MaxFlow()獲取最大流
*/
class C_Dinic
{
public:
static const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int u, v, c, f;
Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
{
u = _u, v = _v, c = _c, f = _f;
}
};
/*====================*/
int n, s, t;
/*====================*/
vector<Edge>edge;
vector<vector<int>>G;
/*====================*/
C_Dinic(void)
{
n = 2, s = 1, t = 2;
}
private:
vector<int>cur;//當前弧最佳化
vector<int>d, vis;//圖分層
/*====================*/
bool BFS(void)
{
fill(d.begin(), d.end(), 0);
fill(vis.begin(), vis.end(), 0);
d[s] = 0; vis[s] = 1;
queue<int>q; q.push(s);
while (!q.empty())
{
int x = q.front(); q.pop();
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (!vis[e.v] && e.c > e.f)
{
vis[e.v] = 1; d[e.v] = d[x] + 1; q.push(e.v);
}
}
}
return vis[t];
}
int DFS(int x, int k)
{
int flow = 0, f;
if (x == t || k == 0) return k;
for (int& i = cur[x]; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
{
e.f += f; edge[G[x][i] ^ 1].f -= f;
flow += f; k -= f; if (k == 0) break;
}
}
return flow;
}
public:
int S(void) { return s; }
int T(void) { return t; }
/*====================*/
int AddVertex(void)
{
return ++n;
}
int AddEdge(int u, int v, int c)
{
edge.push_back(Edge(u, v, c, 0));
edge.push_back(Edge(v, u, 0, 0));
G[u].push_back(edge.size() - 2);
G[v].push_back(edge.size() - 1);
return edge.size() - 2;
}
/*====================*/
void Init(void)
{
d.assign(n + 1, int());
vis.assign(n + 1, int());
cur.assign(n + 1, int());
G.assign(n + 1, vector<int>());
}
/*====================*/
int MaxFlow(void)
{
int flow = 0;
while (BFS())
{
flow += DFS(s, INF);
fill(cur.begin(), cur.end(), 0);
}
return flow;
}
};
Dinic-Scaling
namespace _Dinic
{
const int N = 1e5 + 10;
const int M = 1e5 + 10;
/*====================*/
const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int u, v, c, f;
Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
{
u = _u, v = _v, c = _c, f = _f;
}
friend bool operator<(const Edge& a, const Edge& b)
{
return a.c > b.c;
}
};
/*====================*/
int d[N];//圖分層
int cur[N];//當前弧最佳化
Edge _edge[M];//即將加入流網路的邊
int n, m, s, t;//點,邊,源,匯
vector<int>G[N];//鄰接表
Edge edge[2 * M]; int cnt;//邊
/*====================*/
void AddEdge(int u, int v, int c)
{
edge[cnt++] = Edge(u, v, c, 0);
edge[cnt++] = Edge(v, u, 0, 0);
G[u].push_back(cnt - 2);
}
/*====================*/
bool BFS(void)
{
for (int i = 0; i <= n; ++i)
{
d[i] = INF;
}
queue<int>q; q.push(s); d[s] = 0;
while (!q.empty())
{
int x = q.front(); q.pop();
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (d[e.v] >= INF && e.c > e.f)
{
d[e.v] = d[x] + 1; q.push(e.v);
}
}
}
return d[t] < INF;
}
int DFS(int x, int k)
{
int flow = 0, f;
if (x == t || k == 0) return k;
for (int& i = cur[x]; i < G[x].size(); ++i)
{
Edge& e = edge[G[x][i]];
if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
{
e.f += f; edge[G[x][i] ^ 1].f -= f;
flow += f; k -= f; if (k == 0) break;
}
}
return flow;
}
int Dinic(void)
{
int flow = 0;
while (BFS())
{
flow += DFS(s, INF);
for (int i = 1; i <= n; ++i)
{
cur[i] = 0;
}
}
return flow;
}
int MaxFlow(void)
{
int flow = 0;
sort(_edge, _edge + m);
for (int type : {0, 1})
{
for (int p = 1 << 30, i = 0; p; p /= 2)
{
while (i < m && _edge[i].c >= p)
{
if (type == 0)AddEdge(_edge[i].u, _edge[i].v, _edge[i].c);
if (type == 1)G[_edge[i].v].push_back(i * 2 + 1); i++;
}
flow += Dinic();
}
}
return flow;
}
/*====================*/
int Init(void)
{
cnt = 0;
cin >> n >> m >> s >> t;
for (int i = 1; i <= n; ++i)
{
G[i].clear();
}
for (int i = 0; i < m; ++i)
{
int u, v, c;
cin >> u >> v >> c;
_edge[i] = Edge(u, v, c);
}
return MaxFlow();
}
}
Dinic-最後反悔
/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MaxFlow()獲取最大流
*/
class C_Dinic
{
public:
static const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int u, v, c, f;
Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
{
u = _u, v = _v, c = _c, f = _f;
}
};
/*====================*/
int n = 2, s = 1, t = 2;
/*====================*/
vector<Edge>edge;
vector<vector<int>>G1;
vector<vector<int>>G2;
private:
vector<int>cur;//當前弧最佳化
vector<int>d, vis;//圖分層
/*====================*/
bool BFS(void)
{
fill(d.begin(), d.end(), 0);
fill(vis.begin(), vis.end(), 0);
d[s] = 0; vis[s] = 1;
queue<int>q; q.push(s);
while (!q.empty())
{
int x = q.front(); q.pop();
for (int i = 0; i < G1[x].size(); ++i)
{
Edge& e = edge[G1[x][i]];
if (!vis[e.v] && e.c > e.f)
{
vis[e.v] = 1; d[e.v] = d[x] + 1; q.push(e.v);
}
}
}
return vis[t];
}
int DFS(int x, int k)
{
int flow = 0, f;
if (x == t || k == 0) return k;
for (int& i = cur[x]; i < G1[x].size(); ++i)
{
Edge& e = edge[G1[x][i]];
if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
{
e.f += f; edge[G1[x][i] ^ 1].f -= f;
flow += f; k -= f; if (k == 0) break;
}
}
return flow;
}
public:
int S(void) { return s; }
int T(void) { return t; }
/*====================*/
int AddVertex(void)
{
return ++n;
}
int AddEdge(int u, int v, int c)
{
edge.push_back(Edge(u, v, c, 0));
edge.push_back(Edge(v, u, 0, 0));
G1[u].push_back(edge.size() - 2);
G2[v].push_back(edge.size() - 1);
return edge.size() - 2;
}
/*====================*/
void Init(void)
{
d.assign(n + 1, int());
vis.assign(n + 1, int());
cur.assign(n + 1, int());
G1.assign(n + 1, vector<int>());
G2.assign(n + 1, vector<int>());
}
/*====================*/
int MaxFlow(void)
{
int flow = 0;
while (BFS())
{
flow += DFS(s, INF);
fill(cur.begin(), cur.end(), 0);
}
for (int i = 1; i <= n; ++i)
{
for (auto idx : G2[i])
{
G1[i].push_back(idx);
}
}
while (BFS())
{
flow += DFS(s, INF);
fill(cur.begin(), cur.end(), 0);
}
return flow;
}
};
費用流
EK
namespace _EK
{
const int N = 1e5 + 10;
const int M = 1e5 + 10;
/*====================*/
const int INF = 0X3F3F3F3F;
/*====================*/
struct Edge
{
int next, v, c, w;
Edge(int _next = 0, int _v = 0, int _c = 0, int _w = 0)
{
next = _next, v = _v, c = _c, w = _w;
}
};
/*====================*/
int n, m, s, t;
int maxflow, mincost;
Edge edge[2 * M]; int head[N], cnt;
int dis[N], pre[N], incf[N]; bool vis[N];
/*====================*/
void AddEdge(int u, int v, int c, int w)
{
edge[cnt] = Edge(head[u], v, c, +w); head[u] = cnt++;
edge[cnt] = Edge(head[v], u, 0, -w); head[v] = cnt++;
}
/*====================*/
bool SPFA(void)
{
memset(dis, 0X3F, sizeof(dis));
queue<int> q; q.push(s);
dis[s] = 0, incf[s] = INF, incf[t] = 0;
while (!q.empty())
{
int u = q.front(); q.pop(); vis[u] = false;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v, c = edge[i].c, w = edge[i].w;
if (!c || dis[v] <= dis[u] + w) continue;
dis[v] = dis[u] + w, incf[v] = min(c, incf[u]), pre[v] = i;
if (!vis[v])q.push(v), vis[v] = true;
}
}
return incf[t];
}
int MinCost(void)
{
while (SPFA())
{
maxflow += incf[t];
for (int u = t; u != s; u = edge[pre[u] ^ 1].v)
{
edge[pre[u]].c -= incf[t];
edge[pre[u] ^ 1].c += incf[t];
mincost += incf[t] * edge[pre[u]].w;
}
}
return mincost;
}
/*====================*/
int Init(void)
{
cin >> n >> m >> s >> t;
mincost = maxflow = cnt = 0;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; ++i)
{
int u, v, c, w;
cin >> u >> v >> c >> w;
AddEdge(u, v, c, w);
}
return MinCost();
}
}
ZKW費用流
/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MinCost()獲取最小費用
*/
class C_ZKW
{
public:
static const int INF = 0X7FFFFFFF;
/*====================*/
struct Edge
{
int u, v, c, w;
Edge(int _u = 0, int _v = 0, int _c = 0, int _w = 0)
{
u = _u, v = _v, c = _c, w = _w;
}
};
/*====================*/
int n = 2, s = 1, t = 2;
/*====================*/
vector<Edge>edge;
vector<vector<int>>G;
int mincost, maxflow;
private:
vector<int>dis;
vector<bool>vis;
/*====================*/
bool SPFA(void)
{
fill(vis.begin(), vis.end(), false);
fill(dis.begin(), dis.end(), INF);
vis[t] = true, dis[t] = 0;
deque<int> q; q.push_back(t);
while (!q.empty())
{
int x = q.front(); q.pop_front(), vis[x] = false;
if (!q.empty() && dis[q.front()] > dis[q.back()])
{
swap(q.front(), q.back());
}
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e1 = edge[G[x][i] ^ 0];
Edge& e2 = edge[G[x][i] ^ 1];
if (e2.c != 0 && dis[e1.v] > dis[x] - e1.w)
{
dis[e1.v] = dis[x] - e1.w;
if (!vis[e1.v])
{
vis[e1.v] = true;
if (!q.empty() && dis[e1.v] < dis[q.front()])
{
q.push_front(e1.v);
}
else
{
q.push_back(e1.v);
}
}
}
}
}
return dis[s] < INF;
}
int DFS(int x, int k)
{
vis[x] = true; int flow = 0, f;
if (x == t || k == 0) return k;
for (int i = 0; i < G[x].size(); ++i)
{
Edge& e1 = edge[G[x][i] ^ 0];
Edge& e2 = edge[G[x][i] ^ 1];
if (vis[e1.v] || e1.c == 0)continue;
if (dis[x] - e1.w == dis[e1.v] && (f = DFS(e1.v, min(k, e1.c))) > 0)
{
e1.c -= f, e2.c += f; flow += f, k -= f;
mincost += f * e1.w; if (k == 0) break;
}
}
return flow;
}
public:
int S(void) { return s; }
int T(void) { return t; }
/*====================*/
int AddVertex(void)
{
return ++n;
}
int AddEdge(int u, int v, int c, int w)
{
edge.push_back(Edge(u, v, c, +w));
edge.push_back(Edge(v, u, 0, -w));
G[u].push_back(edge.size() - 2);
G[v].push_back(edge.size() - 1);
return edge.size() - 2;
}
/*====================*/
void Init(void)
{
dis.assign(n + 1, int());
vis.assign(n + 1, int());
G.assign(n + 1, vector<int>());
}
/*====================*/
int MinCost(void)
{
maxflow = mincost = 0;
while (SPFA())
{
vis[t] = true;
while (vis[t])
{
fill(vis.begin(), vis.end(), false);
maxflow += DFS(s, INF);
}
}
return mincost;
}
};
支配樹
namespace Lengauer_Tarjan
{
struct Edge
{
int v, x;
Edge(int _v = 0, int _x = 0)
{
v = _v, x = _x;
}
};
/*====================*/
int n, m;
Edge edge[M * 3]; int head[3][N], tot;
int idx[N], dfn[N], dfc;
int fa[N], fth[N], mn[N], idm[N], sdm[N];
/*====================*/
void Add(int x, int u, int v)
{
edge[head[x][u] = ++tot] = Edge(v, head[x][u]);
}
void Add(int u, int v)
{
Add(0, u, v); Add(1, v, u);
}
void DFS(int u)
{
idx[dfn[u] = ++dfc] = u;
for (int i = head[0][u]; i; i = edge[i].x)
{
int v = edge[i].v;
if (!dfn[v])
{
DFS(v), fth[v] = u;
}
}
}
int Find(int x)
{
if (fa[x] == x)
{
return x;
}
int tmp = fa[x];
fa[x] = Find(fa[x]);
if (dfn[sdm[mn[tmp]]] < dfn[sdm[mn[x]]])
{
mn[x] = mn[tmp];
}
return fa[x];
}
void Tarjan(int st)
{
DFS(st);
for (int i = 1; i <= n; ++i)
{
fa[i] = sdm[i] = mn[i] = i;
}
for (int i = dfc; i >= 2; --i)
{
int u = idx[i], res = INF;
for (int j = head[1][u]; j; j = edge[j].x)
{
int v = edge[j].v; Find(v);
if (dfn[v] < dfn[u])
{
res = min(res, dfn[v]);
}
else
{
res = min(res, dfn[sdm[mn[v]]]);
}
}
sdm[u] = idx[res];
fa[u] = fth[u];
Add(2, sdm[u], u);
u = fth[u];
for (int j = head[2][u]; j; j = edge[j].x)
{
int v = edge[j].v; Find(v);
if (sdm[mn[v]] == u)
{
idm[v] = u;
}
else
{
idm[v] = mn[v];
}
}
head[2][u] = 0;
}
for (int i = 2; i <= dfc; ++i)
{
int u = idx[i];
if (idm[u] != sdm[u])
{
idm[u] = idm[idm[u]];
}
}
}
/*====================*/
void Init(int s)
{
Tarjan(s);
tot = dfc = 0;
for (int i = 1; i <= n; ++i)
{
dfn[i] = head[0][i] = head[1][i] = head[2][i] = 0;
}
}
//樹上連邊idm[i] -> i;
}
拓撲排序
void TopSort(C_Graph& G)
{
vector<int>indegree(G.n + 1, 0); queue<int>q;
for (const auto& edge : G.edge)indegree[edge.v]++;
for (int i = 1; i <= G.n; ++i)if (indegree[i] == 0)q.push(i);
while (!q.empty())
{
int cur = q.front(); q.pop(); cout << cur << " ";
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = G(G[cur][i]).node(cur);
if (--indegree[nxt] == 0)q.push(nxt);
}
}
}
差分約束
namespace _SDC
{
/*
存在負環時無解
記得建立一個超級源點
A-B<=W的不等式,由B->A,邊權為W
跑最短路時為最大差值,跑最長路時為最小差值
*/
const int N = 1e5 + 10;
/*====================*/
const int INF = 0X3F3F3F3F;
/*====================*/
int dis[N]; int cnt[N]; bool vis[N];
/*====================*/
bool Init(void)
{
G[0].clear(); cnt[0] = 0;
for (int i = 1; i <= n; ++i)
{
G[0].push_back(++m);
edge[m] = Edge(0, i, 0);
dis[i] = INF, vis[i] = false, cnt[i] = 0;
}
queue<int>q; dis[0] = 0; q.push(0);
while (!q.empty())
{
int cur = q.front(); q.pop(); vis[cur] = false;
for (int i = 0; i < G[cur].size(); ++i)
{
int val = edge[G[cur][i]].w;
int nxt = edge[G[cur][i]].node(cur);
if (dis[nxt] > dis[cur] + val)
{
cnt[nxt] = cnt[cur] + 1;
dis[nxt] = dis[cur] + val;
if (cnt[nxt] > n)return false;
if (!vis[nxt])
{
q.push(nxt); vis[nxt] = true;
}
}
}
}
return true;
}
}
圖的連通性
雙連通分量
邊雙連通分量
namespace _E_DCC
{
const int N = 1e5 + 10;
/*====================*/
int belong[N], cnt;
int dfn[N], low[N], num;
/*====================*/
void Tarjan(int cur, int in_edge)
{
dfn[cur] = low[cur] = ++num;
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = edge[G[cur][i]].node(cur);
if (!dfn[nxt])
{
Tarjan(nxt, G[cur][i]);
low[cur] = min(low[cur], low[nxt]);
if (low[nxt] > dfn[cur])
{
edge[G[cur][i]].bridge = true;
}
}
else if (i != in_edge)
{
low[cur] = min(low[cur], dfn[nxt]);
}
}
}
void DFS(int cur)
{
belong[cur] = cnt;
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = edge[G[cur][i]].node(cur);
if (edge[G[cur][i]].bridge)continue;
if (belong[nxt])continue; DFS(nxt);
}
}
/*====================*/
void Init(void)
{
for (int i = 1; i <= n; ++i)
{
if (!dfn[i])Tarjan(i, 0);
}
for (int i = 1; i <= n; ++i)
{
if (!belong[i])cnt++, DFS(i);
}
}
}
點雙連通分量
namespace _V_DCC
{
const int N = 1e5 + 10;
/*====================*/
vector<int>dcc[N];
bool cut[N]; int cnt;
stack<int>lib; int root;
int dfn[N], low[N], num;
/*====================*/
void Tarjan(int cur)
{
int flag = 0; lib.push(cur);
dfn[cur] = low[cur] = ++num;
if (cur == root && G[cur].size() == 0)
{
dcc[++cnt].push_back(cur); return;
}
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = edge[G[cur][i]].node(cur);
if (!dfn[nxt])
{
Tarjan(nxt);
low[cur] = min(low[cur], low[nxt]);
if (low[nxt] >= dfn[cur])
{
flag++; cnt++; int top;
if (cur != root || flag > 1)
{
cut[cur] = true;
}
do
{
top = lib.top(); lib.pop();
dcc[cnt].push_back(top);
} while (top != nxt);
dcc[cnt].push_back(cur);
}
}
else
{
low[cur] = min(low[cur], dfn[nxt]);
}
}
}
/*====================*/
void Init(void)
{
for (int i = 1; i <= n; ++i)
{
if (!dfn[i])Tarjan(root = i);
}
}
}
獲取點雙內部的邊
void Tarjan(int cur, int e)
{
dfn[cur] = low[cur] = ++num;
if (cur != root || G[cur].size() != 0)
{
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = edge[G[cur][i]].node(cur);
if (!dfn[nxt])
{
lib.push(G[cur][i]); Tarjan(nxt, G[cur][i]);
low[cur] = min(low[cur], low[nxt]);
if (low[nxt] >= dfn[cur])
{
cnt++; int top;
do
{
top = lib.top(); lib.pop();
dcc[cnt].push_back(edge[top].w);
} while (top != G[cur][i]);
}
}
else
{
if (dfn[nxt] < dfn[cur] && G[cur][i] != e)
{
lib.push(G[cur][i]);
}
low[cur] = min(low[cur], dfn[nxt]);
}
}
}
}
強連通分量
namespace _SCC
{
const int N = 1e5 + 10;
/*====================*/
int belong[N];
int dfn[N], low[N], num;
stack<int>lib; int ins[N];
vector<int>scc[N]; int cnt;
/*====================*/
void Tarjan(int cur)
{
lib.push(cur); ins[cur] = 1;
dfn[cur] = low[cur] = ++num;
for (int i = 0; i < G[cur].size(); ++i)
{
int nxt = edge[G[cur][i]].node(cur);
if (!dfn[nxt])
{
Tarjan(nxt);
low[cur] = min(low[cur], low[nxt]);
}
else if (ins[nxt])
{
low[cur] = min(low[cur], dfn[nxt]);
}
}
if (dfn[cur] == low[cur])
{
cnt++; int top;
do
{
top = lib.top(); lib.pop(); ins[top] = 0;
belong[top] = cnt; scc[cnt].push_back(top);
} while (top != cur);
}
}
/*====================*/
void Init(void)
{
num = cnt = 0;
for (int i = 1; i <= n; ++i)
{
dfn[i] = low[i] = 0;
}
for (int i = 1; i <= n; ++i)
{
if (!dfn[i])Tarjan(i);
}
}
}
最小樹形圖
有向有環圖
挖坑:朱劉演算法
有向無環圖
namespace _DMST
{
const int N = 1e5 + 10;
/*====================*/
const int INF = 0X7FFFFFFF;
/*====================*/
int val[N], sum;
/*====================*/
void Init(void)
{
sum = 0;
for (int i = 1; i <= n; ++i)
{
val[i] = INF;
}
for (int i = 1; i <= m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
val[v] = min(val[v], w);
}
for (int i = 1; i <= n; ++i)
{
if (val[i] != INF)
{
sum += val[i];
}
}
}
}