图论
最短路
迪杰斯特拉
vector<pair<int, int>> e[MAXN];
void addedge(int u, int v, int w) {
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
bool vis[MAXN];
int dist[MAXN];
void dijkstra(int s) {
struct GraphNode {
int u, d;
bool operator <(const GraphNode& p) const {
return p.d < d;
}
};
priority_queue<GraphNode> q;
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0, q.push({s, dist[s]});
while (!q.empty()) {
int u = q.top().u; q.pop();
if (vis[u]) continue;
vis[u] = true;
for (auto& [v, w]: e[u]) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
q.push({v, dist[v]});
}
}
}
}
struct edge {
int to, next, val;
} e[MAXN << 1];
int head[MAXN], idx;
void addedge(int u, int v, int w) {
e[++idx] = {v, head[u], w};
head[u] = idx;
}
bool vis[MAXN];
int dist[MAXN], pre[MAXN];
void dijkstra(int s) {
struct GraphNode {
int u, d;
bool operator <(const GraphNode& p) const {
return p.d < d;
}
};
priority_queue<GraphNode> q;
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0, q.push({s, dist[s]});
while (!q.empty()) {
int u = q.top().u; q.pop();
if (vis[u]) continue;
vis[u] = true;
for (auto& [v, w]: e[u]) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pre[v] = u;
q.push({v, dist[v]});
}
}
}
}
// 无解特判否则死循环
vector<int> path;
void dfs(int s, int t) {
if (s == t) {
path.push_back(s);
return ;
}
dfs(s, pre[t]);
path.push_back(s);
}
SPFA
双优化
vector<pair<int, int>> e[MAXN];
void addedge(int u, int v, int w) {
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
bool inq[MAXN];
int dist[MAXN];
void spfa(int s) {
deque<int> q;
memset(inq, false, sizeof(inq));
memset(dist, 0x3f, sizeof(dist));
inq[s] = true, dist[s] = 0, q.push_back(s);
int cnt = 0, val = 0;
while (!q.empty()) {
int u = q.front(); q.pop_front();
// 如果有负边, 可以去掉这个优化
if (dist[u] * cnt > val) {
q.push_back(u);
continue;
}
inq[u] = false, --cnt, val -= dist[u];
for (auto& [v, w]: e[u]) {
int v = e[i].to, w = e[i].val;
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
if (!inq[v]) {
inq[v] = true, ++cnt, val += dist[v];
if (!q.empty() && dist[v] < dist[q.front()]) {
q.push_front(v);
} else {
q.push_back(v);
}
}
}
}
}
}
判断负环
vector<pair<int, int>> e[MAXN];
void addedge(int u, int v, int w) {
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
bool inq[MAXN];
int dist[MAXN], neg[MAXN];
bool spfa(int s, int n) {
memset(neg, 0, sizeof(neg));
memset(inq, false, sizeof(inq));
memset(dist, 0x3f, sizeof(dist));
queue<int> q;
inq[s] = true, dist[s] = 0, q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
inq[u] = false;
for (auto& [v, w]: e[u]) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
neg[v] = neg[u] + 1;
if (neg[v] >= n) {
return true;
}
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
return false;
}
弗洛伊德
// 读入前初始化图为无穷大
int g[MAXN][MAXN];
void floyd(int n) {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (g[i][j] > g[i][k] + g[k][j]) {
g[i][j] = g[i][k] + g[k][j];
}
}
}
}
}
打印欧拉路径
// 找到入度为0的点, 没有的话取任意点
vector<int> path;
void dfs(int u) {
while (!e[u].empty()) {
int v = e[u].back();
e[u].pop_back();
dfs(v);
}
path.push_back(u);
};
reverse(path.begin(), path.end());
tarjan
scc
class SCC {
public:
SCC(int _n): n(_n), low(_n), dfn(_n), belong(_n), ins(_n) {
idx = sccn = 0;
}
void addedge(int u, int v) {
e[u].push_back(v);
// e[v].push_back(u);
}
void dfs(int u) {
dfn[u] = low[u] = ++idx;
pt.push(u), ins[u] = true;
for (int& v: e[u]) {
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
} else if (ins[v]) {
low[u] = min(low[u], dfn[v]);
}
}
int top;
if (low[u] == dfn[u]) {
do {
top = pt.top(), pt.pop();
ins[top] = false, belong[top] = sccn;
} while (u != top);
++sccn;
}
}
void tarjan() {
for (int i = 0; i < n; ++i) {
if (!dfn[i]) {
dfs(i);
}
}
}
vector<vector<int>> groups() {
vector<vector<int>> g(sccn);
for (int i = 0; i < n; ++i) {
g[belong[i]].push_back(i);
}
return g;
}
int belongOf(int u) {
return belong.at(u);
}
private:
int n, idx, sccn;
vector<int> low, dfn, belong;
stack<int> pt;
vector<bool> ins;
unorderer_map<int, vector<int>> e;
};
割点割边
// 判断割边判断条件表达式改成low[v] > dfn[u]
vector<int> e[MAXN];
void addedge(int u, int v) {
e[u].push_back(v);
e[v].push_back(u);
}
bool iscut[MAXN];
int low[MAXN], dfn[MAXN], idx;
void dfs(int u, int root) {
dfn[u] = low[u] = ++idx;
int son = 0;
for (int v: e[u]) {
if (!dfn[v]) {
dfs(v, root);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u] && u != root) {
iscut[u] = true;
} else if (u == root) {
++son;
}
} else {
low[u] = min(low[u], dfn[v]);
}
}
if (u == root && son >= 2) {
iscut[root] = true;
}
}
int countCuts(int n) {
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) {
dfs(i, i);
}
}
int res = 0;
for (int i = 1; i <= n; ++i) {
res += iscut[i];
}
return res;
}
一般图最大匹配
queue<int> q;
vector<int> e[MAXN];
int fa[MAXN], ID[MAXN], tec, vis[MAXN], match[MAXN], pre[MAXN];
void init(int n) {
tec = 0;
for (int i = 1; i <= n; ++i) {
e[i].clear();
ID[i] = match[i] = 0;
}
}
void addedge(int u, int v) {
e[u].push_back(v);
}
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int lca(int x, int y) {
++tec;
while (true) {
if (x) {
x = find(x);
if (ID[x] == tec) {
return x;
} else {
ID[x] = tec;
x = pre[match[x]];
}
}
swap(x, y);
}
}
void shrink(int x, int y, int lca) {
while (find(x) != lca) {
pre[x] = y;
y = match[x];
if (vis[y] == 2) {
vis[y] = 1;
q.push(y);
}
if (find(x) == x) {
fa[x] = lca;
}
if (find(y) == y) {
fa[y] = lca;
}
x = pre[y];
}
}
bool aug(int s, int n) {
for (int i = 1; i <= n; ++i) {
fa[i] = i;
vis[i] = pre[i] = 0;
}
while (!q.empty()) {
q.pop();
}
q.push(s), vis[s] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v: e[u]) {
if (find(u) == find(v) || vis[v] == 2) {
continue;
}
if (!vis[v]) {
vis[v] = 2;
pre[v] = u;
if (!match[v]) {
int last;
for (int i = v; i; i = last) {
last = match[pre[i]];
match[i] = pre[i];
match[pre[i]] = i;
}
return true;
}
vis[match[v]] = 1;
q.push(match[v]);
} else {
int f = lca(u, v);
shrink(u, v, f);
shrink(v, u, f);
}
}
}
return false;
}
int EMA(int n) {
int res = 0;
for (int i = 1; i <= n; ++i) {
res += (!match[i] && aug(i, n));
}
return res;
}
二分图
最大匹配 = 最小点覆盖 = 总点数 - 最大独立集 = 总点数 - 最小路径覆盖
最小点覆盖: 从图中选出最少的点, 使得图中的每一条边至少有一个顶点被选
最大独立集: 在一个图中, 找到一个最大的集合包含的所有点相互之间都不存在连边
最小路径覆盖: 在一个有向图中, 找出最少的路径, 使得这些路径经过了所有的点
二分图最大匹配
vector<int> e[MAXN];
int vis[MAXN], match[MAXN];
bool dfs(int u, int sgn) {
if (vis[u] == sgn) return false;
vis[u] = sgn;
for (int& v: e[u]) {
if (!match[v] || dfs(match[v], sgn)) {
match[v] = u;
return true;
}
}
return false;
}
int hungary(int n) {
int res = 0;
memset(vis, false, sizeof(vis));
memset(match, 0, sizeof(match));
for (int i = 1; i <= n; ++i) {
res += dfs(i, i);
}
return res;
}
染色法判断二分图
int col[MAXN];
vector<int> e[MAXN];
bool dfp(int u, int c) {
col[u] = c;
for (int& v: e[u]) {
if (col[v]) {
if (col[v] == c) {
return false;
}
} else if (!dfp(v, 3 - c)) {
return false;
}
}
return true;
}
bool isBG(int n) {
for (int i = 1; i <= n; ++i) {
if (col[i]) {
continue;
}
if (!dfp(i, 1)) {
return false;
}
}
return true;
}
最小生成树
普利姆
struct edge {
int to, next, val;
} e[MAXN << 1];
int head[MAXN], idx;
void addedge(int u, int v, int w) {
e[++idx] = edge{v, head[u], w};
head[u] = idx;
}
bool vis[MAXN];
int dist[MAXN];
int prim(int n) {
struct PrimeNode {
int u, dist;
bool operator <(const PrimeNode& p) const {
return p.dist < dist;
}
};
priority_queue<PrimeNode> Q;
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
dist[1] = 0, Q.push({1, 0});
int cnt = 0, res = 0;
while (!Q.empty()) {
int u = Q.top().u; Q.pop();
if (vis[u]) continue;
vis[u] = true, ++cnt, res += dist[u];
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to, w = e[i].val;
if (w < dist[v]) {
dist[v] = w;
Q.push({v, dist[v]});
}
}
}
return cnt == n - 1 ? res : -1;
}
克鲁斯卡尔
struct edge {
int u, v, w;
bool operator <(const edge& p) const {
return w < p.w;
}
} e[MAXN];
int kruskal(int n, int m) {
vector<int> fa(n + 1);
iota(fa.begin(), fa.end(), 0);
function<int(int)> find = [&](int x) -> int {
return fa[x] == x ? x : fa[x] = find(fa[x]);
};
auto merge = [&](int x, int y) -> void {
fa[find(x)] = find(y);
};
sort(e + 1, e + m + 1);
int cnt = 0, res = 0;
for (int i = 1; i <= m; ++i) {
auto& [u, v, w] = e[i];
int x = find(u);
int y = find(v);
if (x == y) {
continue;
}
merge(x, y), ++cnt, res += w;
if (cnt == n - 1) {
break;
}
}
return cnt == n - 1 ? res : -1;
}
网络流
最大流
const int INF = 0x3f3f3f3f;
struct edge {
int to, next, val;
} e[MAXN << 1];
int head[MAXN], idx = 1;
void add(int u, int v, int w) {
e[++idx] = edge{v, head[u], w};
head[u] = idx;
}
void addedge(int u, int v, int w) {
add(u, v, w);
add(v, u, 0);
}
int depth[MAXN], cur[MAXN];
bool bfs(int s, int t) {
queue<int> Q;
memset(depth, 0x3f, sizeof(depth));
cur[s] = head[s], depth[s] = 0, Q.push(s);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (u == t) return true;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to, w = e[i].val;
if (depth[v] == INF && w) {
cur[v] = head[v];
depth[v] = depth[u] + 1;
Q.push(v);
}
}
}
return false;
}
int dfs(int u, int t, int limit) {
if (!limit || u == t) return limit;
int flow = 0;
for (int i = cur[u]; i; i = e[i].next) {
cur[u] = i;
int v = e[i].to, w = e[i].val;
if (depth[v] == depth[u] + 1 && w) {
int k = dfs(v, t, min(limit, w));
flow += k, limit -= k;
e[i].val -= k, e[i ^ 1].val += k;
if (!limit) break;
}
}
return flow;
}
int maxflow(int s, int t) {
int maxflow = 0;
while (bfs(s, t)) {
maxflow += dfs(s, t, INF);
}
return maxflow;
}
最小费用最大流
const int INF = 0x3f3f3f3f;
struct edge {
int to, next;
int flow, cost;
} e[MAXN << 1];
int head[MAXN], idx = 1;
void add(int u, int v, int flow, int cost) {
e[++idx] = {v, head[u], flow, cost};
head[u] = idx;
}
void addedge(int u, int v, int flow, int cost) {
add(u, v, flow, cost);
add(v, u, 0, -cost);
}
bool vis[MAXN];
int dist[MAXN];
bool spfa(int s, int t) {
queue<int> Q;
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0, Q.push(s);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
vis[u] = false;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to, w = e[i].cost;
if (e[i].flow && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
if (!vis[v]) {
vis[v] = true;
Q.push(v);
}
}
}
}
return dist[t] != INF;
}
int mincost, maxflow, cur[MAXN];
int dfs(int u, int t, int limit) {
if (!limit || u == t) return limit;
vis[u] = true;
int flow = 0;
for (int i = head[u]; i; i = e[i].next) {
cur[u] = i;
int v = e[i].to, w = e[i].flow;
if (!vis[v] && e[i].flow && dist[v] == dist[u] + e[i].cost) {
int k = dfs(v, t, min(limit, w));
if (!k) continue;
flow += k, limit -= k;
e[i].flow -= k, e[i ^ 1].flow += k;
mincost += e[i].cost * k;
if (!limit) break;
}
}
vis[u] = false;
return flow;
}
pair<int, int> mcmf(int s, int t) {
while (spfa(s, t)) {
memcpy(cur, head, sizeof(head));
maxflow += dfs(s, t, INF);
}
return {mincost, maxflow};
}
最大流
namespace atcoder {
namespace internal {
template <class T> struct simple_queue {
std::vector<T> payload;
int pos = 0;
void reserve(int n) { payload.reserve(n); }
int size() const { return int(payload.size()) - pos; }
bool empty() const { return pos == int(payload.size()); }
void push(const T& t) { payload.push_back(t); }
T& front() { return payload[pos]; }
void clear() {
payload.clear();
pos = 0;
}
void pop() { pos++; }
};
} // namespace internal
template <class Cap> struct mf_graph {
public:
mf_graph() : _n(0) {}
explicit mf_graph(int n) : _n(n), g(n) {}
int add_edge(int from, int to, Cap cap) {
assert(0 <= from && from < _n);
assert(0 <= to && to < _n);
assert(0 <= cap);
int m = int(pos.size());
pos.push_back({from, int(g[from].size())});
int from_id = int(g[from].size());
int to_id = int(g[to].size());
if (from == to) to_id++;
g[from].push_back(_edge{to, to_id, cap});
g[to].push_back(_edge{from, from_id, 0});
return m;
}
struct edge {
int from, to;
Cap cap, flow;
};
edge get_edge(int i) {
int m = int(pos.size());
assert(0 <= i && i < m);
auto _e = g[pos[i].first][pos[i].second];
auto _re = g[_e.to][_e.rev];
return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
}
std::vector<edge> edges() {
int m = int(pos.size());
std::vector<edge> result;
for (int i = 0; i < m; i++) {
result.push_back(get_edge(i));
}
return result;
}
void change_edge(int i, Cap new_cap, Cap new_flow) {
int m = int(pos.size());
assert(0 <= i && i < m);
assert(0 <= new_flow && new_flow <= new_cap);
auto& _e = g[pos[i].first][pos[i].second];
auto& _re = g[_e.to][_e.rev];
_e.cap = new_cap - new_flow;
_re.cap = new_flow;
}
Cap flow(int s, int t) {
return flow(s, t, std::numeric_limits<Cap>::max());
}
Cap flow(int s, int t, Cap flow_limit) {
assert(0 <= s && s < _n);
assert(0 <= t && t < _n);
assert(s != t);
std::vector<int> level(_n), iter(_n);
internal::simple_queue<int> que;
auto bfs = [&]() {
std::fill(level.begin(), level.end(), -1);
level[s] = 0;
que.clear();
que.push(s);
while (!que.empty()) {
int v = que.front();
que.pop();
for (auto e : g[v]) {
if (e.cap == 0 || level[e.to] >= 0) continue;
level[e.to] = level[v] + 1;
if (e.to == t) return;
que.push(e.to);
}
}
};
auto dfs = [&](auto self, int v, Cap up) {
if (v == s) return up;
Cap res = 0;
int level_v = level[v];
for (int& i = iter[v]; i < int(g[v].size()); i++) {
_edge& e = g[v][i];
if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
Cap d =
self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
if (d <= 0) continue;
g[v][i].cap += d;
g[e.to][e.rev].cap -= d;
res += d;
if (res == up) return res;
}
level[v] = _n;
return res;
};
Cap flow = 0;
while (flow < flow_limit) {
bfs();
if (level[t] == -1) break;
std::fill(iter.begin(), iter.end(), 0);
Cap f = dfs(dfs, t, flow_limit - flow);
if (!f) break;
flow += f;
}
return flow;
}
std::vector<bool> min_cut(int s) {
std::vector<bool> visited(_n);
internal::simple_queue<int> que;
que.push(s);
while (!que.empty()) {
int p = que.front();
que.pop();
visited[p] = true;
for (auto e : g[p]) {
if (e.cap && !visited[e.to]) {
visited[e.to] = true;
que.push(e.to);
}
}
}
return visited;
}
private:
int _n;
struct _edge {
int to, rev;
Cap cap;
};
std::vector<std::pair<int, int>> pos;
std::vector<std::vector<_edge>> g;
};
} // namespace atcoder
using namespace atcoder;
最小费用最大流
namespace atcoder {
namespace internal {
template <class T> struct simple_queue {
std::vector<T> payload;
int pos = 0;
void reserve(int n) { payload.reserve(n); }
int size() const { return int(payload.size()) - pos; }
bool empty() const { return pos == int(payload.size()); }
void push(const T& t) { payload.push_back(t); }
T& front() { return payload[pos]; }
void clear() {
payload.clear();
pos = 0;
}
void pop() { pos++; }
};
template <class E> struct csr {
std::vector<int> start;
std::vector<E> elist;
explicit csr(int n, const std::vector<std::pair<int, E>>& edges)
: start(n + 1), elist(edges.size()) {
for (auto e : edges) {
start[e.first + 1]++;
}
for (int i = 1; i <= n; i++) {
start[i] += start[i - 1];
}
auto counter = start;
for (auto e : edges) {
elist[counter[e.first]++] = e.second;
}
}
};
} // namespace internal
template <class Cap, class Cost> struct mcf_graph {
public:
mcf_graph() {}
explicit mcf_graph(int n) : _n(n) {}
int add_edge(int from, int to, Cap cap, Cost cost) {
assert(0 <= from && from < _n);
assert(0 <= to && to < _n);
assert(0 <= cap);
assert(0 <= cost);
int m = int(_edges.size());
_edges.push_back({from, to, cap, 0, cost});
return m;
}
struct edge {
int from, to;
Cap cap, flow;
Cost cost;
};
edge get_edge(int i) {
int m = int(_edges.size());
assert(0 <= i && i < m);
return _edges[i];
}
std::vector<edge> edges() { return _edges; }
std::pair<Cap, Cost> flow(int s, int t) {
return flow(s, t, std::numeric_limits<Cap>::max());
}
std::pair<Cap, Cost> flow(int s, int t, Cap flow_limit) {
return slope(s, t, flow_limit).back();
}
std::vector<std::pair<Cap, Cost>> slope(int s, int t) {
return slope(s, t, std::numeric_limits<Cap>::max());
}
std::vector<std::pair<Cap, Cost>> slope(int s, int t, Cap flow_limit) {
assert(0 <= s && s < _n);
assert(0 <= t && t < _n);
assert(s != t);
int m = int(_edges.size());
std::vector<int> edge_idx(m);
auto g = [&]() {
std::vector<int> degree(_n), redge_idx(m);
std::vector<std::pair<int, _edge>> elist;
elist.reserve(2 * m);
for (int i = 0; i < m; i++) {
auto e = _edges[i];
edge_idx[i] = degree[e.from]++;
redge_idx[i] = degree[e.to]++;
elist.push_back({e.from, {e.to, -1, e.cap - e.flow, e.cost}});
elist.push_back({e.to, {e.from, -1, e.flow, -e.cost}});
}
auto _g = internal::csr<_edge>(_n, elist);
for (int i = 0; i < m; i++) {
auto e = _edges[i];
edge_idx[i] += _g.start[e.from];
redge_idx[i] += _g.start[e.to];
_g.elist[edge_idx[i]].rev = redge_idx[i];
_g.elist[redge_idx[i]].rev = edge_idx[i];
}
return _g;
}();
auto result = slope(g, s, t, flow_limit);
for (int i = 0; i < m; i++) {
auto e = g.elist[edge_idx[i]];
_edges[i].flow = _edges[i].cap - e.cap;
}
return result;
}
private:
int _n;
std::vector<edge> _edges;
// inside edge
struct _edge {
int to, rev;
Cap cap;
Cost cost;
};
std::vector<std::pair<Cap, Cost>> slope(internal::csr<_edge>& g,
int s,
int t,
Cap flow_limit) {
// variants (C = maxcost):
// -(n-1)C <= dual[s] <= dual[i] <= dual[t] = 0
// reduced cost (= e.cost + dual[e.from] - dual[e.to]) >= 0 for all edge
// dual_dist[i] = (dual[i], dist[i])
std::vector<std::pair<Cost, Cost>> dual_dist(_n);
std::vector<int> prev_e(_n);
std::vector<bool> vis(_n);
struct Q {
Cost key;
int to;
bool operator<(Q r) const { return key > r.key; }
};
std::vector<int> que_min;
std::vector<Q> que;
auto dual_ref = [&]() {
for (int i = 0; i < _n; i++) {
dual_dist[i].second = std::numeric_limits<Cost>::max();
}
std::fill(vis.begin(), vis.end(), false);
que_min.clear();
que.clear();
// que[0..heap_r) was heapified
size_t heap_r = 0;
dual_dist[s].second = 0;
que_min.push_back(s);
while (!que_min.empty() || !que.empty()) {
int v;
if (!que_min.empty()) {
v = que_min.back();
que_min.pop_back();
} else {
while (heap_r < que.size()) {
heap_r++;
std::push_heap(que.begin(), que.begin() + heap_r);
}
v = que.front().to;
std::pop_heap(que.begin(), que.end());
que.pop_back();
heap_r--;
}
if (vis[v]) continue;
vis[v] = true;
if (v == t) break;
// dist[v] = shortest(s, v) + dual[s] - dual[v]
// dist[v] >= 0 (all reduced cost are positive)
// dist[v] <= (n-1)C
Cost dual_v = dual_dist[v].first, dist_v = dual_dist[v].second;
for (int i = g.start[v]; i < g.start[v + 1]; i++) {
auto e = g.elist[i];
if (!e.cap) continue;
// |-dual[e.to] + dual[v]| <= (n-1)C
// cost <= C - -(n-1)C + 0 = nC
Cost cost = e.cost - dual_dist[e.to].first + dual_v;
if (dual_dist[e.to].second - dist_v > cost) {
Cost dist_to = dist_v + cost;
dual_dist[e.to].second = dist_to;
prev_e[e.to] = e.rev;
if (dist_to == dist_v) {
que_min.push_back(e.to);
} else {
que.push_back(Q{dist_to, e.to});
}
}
}
}
if (!vis[t]) {
return false;
}
for (int v = 0; v < _n; v++) {
if (!vis[v]) continue;
// dual[v] = dual[v] - dist[t] + dist[v]
// = dual[v] - (shortest(s, t) + dual[s] - dual[t]) +
// (shortest(s, v) + dual[s] - dual[v]) = - shortest(s,
// t) + dual[t] + shortest(s, v) = shortest(s, v) -
// shortest(s, t) >= 0 - (n-1)C
dual_dist[v].first -= dual_dist[t].second - dual_dist[v].second;
}
return true;
};
Cap flow = 0;
Cost cost = 0, prev_cost_per_flow = -1;
std::vector<std::pair<Cap, Cost>> result = {{Cap(0), Cost(0)}};
while (flow < flow_limit) {
if (!dual_ref()) break;
Cap c = flow_limit - flow;
for (int v = t; v != s; v = g.elist[prev_e[v]].to) {
c = std::min(c, g.elist[g.elist[prev_e[v]].rev].cap);
}
for (int v = t; v != s; v = g.elist[prev_e[v]].to) {
auto& e = g.elist[prev_e[v]];
e.cap += c;
g.elist[e.rev].cap -= c;
}
Cost d = -dual_dist[s].first;
flow += c;
cost += c * d;
if (prev_cost_per_flow == d) {
result.pop_back();
}
result.push_back({flow, cost});
prev_cost_per_flow = d;
}
return result;
}
};
} // namespace atcoder
using namespace atcoder;

浙公网安备 33010602011771号