Solution Set【2023.12.5】
[AHOI2009] 最小割
首先考虑如何处理可行边,对于边 \(\left(u, v\right)\),其为可行边与同时满足下列两个条件互为充要条件:
- \(c_f(u, v) = 0\)
- 在 \(G_f\) 中不存在路径 \(u \rightarrow v\)
首先可以发现若存在 \(G_f\) 使得 \(c_f(u, v) > 0\),那么一定不会割这条边。
若 \(G_f\) 中存在路径 \(u \rightarrow v\),那么可以通过将边 \(\left(u, v\right)\) 的一小部分流量通过 \(G_f\) 中存在路径 \(u \rightarrow v\) 传递。这样之后有 \(c_f(u, v) > 0\),那么一定不会割这条边。
考虑在可行边的基础上添加什么条件才可以使得边为必须边。
可以发现,若对于可行边 \(\left(u, v\right)\),若在 \(G_f\) 上不存在路径使得 \(S \rightarrow u\),那么在 \(G\) 的任意一条路径 \(S \rightarrow u\) 上,均存在令一条可行边,因此边 \(\left(u, v\right)\) 不是必须边。
所以可行边 \(\left(u, v\right)\) 是必须边当且仅当 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\)。
可以发现因为 \(c_f(u, v) = 0\),所以有 \(c_f(v, u) > 0\),即边 \(\left(v, u\right) \in G_f\),所以在 \(G_f\) 上存在路径 \(u \rightarrow v\) 等价于 \(u, v\) 在 \(G_f\) 上位于同一个强连通分量中。同理 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\) 等价于 \(u\) 和 \(S\) 在同一个强连通分量中且 \(v\) 和 \(T\) 在同一个强连通分量中。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<bool> bitset;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;
class Dinic {
private:
struct Edge {
public:
typedef std::vector<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
bool full() const {
return flow == cap;
}
};
typedef std::vector<ValueVector> Graph;
typedef std::vector<ValueVector::iterator> IterVector;
valueType N, M;
Edge::container edges;
Graph G;
ValueVector depth;
IterVector start;
ValueVector belong;
bitset inStack;
ValueVector dfn, low;
std::stack<valueType> stack;
bool Initialized;
public:
explicit Dinic(valueType N, valueType M) : N(N), M(M), edges((M << 1) + 10), G(N + 1), depth(N + 1, 0), start(N + 1), belong(N + 1, 0), inStack(N + 1, false), dfn(N + 1, 0), low(N + 1, 0), Initialized(false){};
void addEdge(valueType from, valueType to, valueType cap, valueType id) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
edges[id << 1] = Edge(to, cap, std::next(edges.begin(), id << 1 | 1));
edges[id << 1 | 1] = Edge(from, 0, std::next(edges.begin(), id << 1));
G[from].emplace_back(id << 1);
G[to].emplace_back(id << 1 | 1);
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: reset before init");
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
edges[iter].flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
for (valueType i = 1; i <= N; ++i)
if (!dfn[i])
tarjan(i);
return result;
}
valueType scc(valueType n) const {
return belong[n];
}
bool full(valueType m) const {
return edges[m].full();
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &iter : G[u]) {
auto const &e = edges[iter];
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &iter = Begin[u]; iter != G[u].end(); ++iter) {
auto e = std::next(edges.begin(), *iter);
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
void tarjan(valueType x) {
static valueType dfsCount = 0, sccCount = 0;
inStack[x] = true;
low[x] = dfn[x] = ++dfsCount;
stack.push(x);
for (auto const &iter : G[x]) {
auto e = std::next(edges.begin(), iter);
if (e->full())
continue;
if (!dfn[e->to]) {
tarjan(e->to);
low[x] = std::min(low[x], low[e->to]);
} else if (inStack[e->to]) {
low[x] = std::min(low[x], dfn[e->to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = stack.top();
stack.pop();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M, S, T;
std::cin >> N >> M >> S >> T;
Dinic dinic(N, M);
TupleVector G;
G.reserve(M);
for (valueType i = 1; i <= M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
G.emplace_back(u, v, w);
dinic.addEdge(u, v, w, i);
}
dinic.init();
dinic.maxFlow(S, T);
for (valueType i = 0; i < M; ++i) {
valueType const id = i + 1;
auto const &[u, v, w] = G[i];
bool A = dinic.full(id << 1) && dinic.scc(u) != dinic.scc(v);
bool B = A && dinic.scc(S) == dinic.scc(u) && dinic.scc(T) == dinic.scc(v);
std::cout << A << ' ' << B << '\n';
}
std::cout << std::flush;
return 0;
}
【模板】最小割树(Gomory-Hu Tree)
通过一些证明可以得出结论:最小割不交叉。
因此在点集中任选两点 \(S, T\),我们可以在整个网络中求出其最小割,并在新树中建边 \((S, T)\),边权为最小割的容量,然后将点集划分为两个子集后继续递归划分。
可以发现一共需要求 \(\mathcal{O}(N)\) 次最小割,因此复杂度为 \(\mathcal{O}(N^3M)\)。
由于 \(N\) 的值很小,故在完成建树后可以将所有路径的最小值预处理出来后 \(\mathcal{O}(1)\) 回答所有询问。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
class Dinic {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
valueType N;
Graph G;
ValueVector depth;
IterVector start;
bool Initialized;
public:
explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType x, valueType y, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[x].emplace_back(y, cap);
G[y].emplace_back(x, cap);
G[x].back().pair = std::prev(G[y].end());
G[y].back().pair = std::prev(G[x].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
return result;
}
bool reachable(valueType n) const {
return depth[n] > 0;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &e = Begin[u]; e != G[u].end(); ++e) {
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
};
void solve(ValueVector const &V, PairMatrix &G, Dinic &dinic) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
G[S].emplace_back(T, weight);
G[T].emplace_back(S, weight);
ValueVector A, B;
for (auto const &iter : V) {
if (dinic.reachable(iter))
A.emplace_back(iter);
else
B.emplace_back(iter);
}
solve(A, G, dinic);
solve(B, G, dinic);
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &dist) {
for (auto const &[to, weight] : G[x]) {
if (to == from)
continue;
dist[to] = std::min(dist[x], weight);
dfs(to, x, G, dist);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
// ++N;
Dinic dinic(N);
for (valueType i = 0; i < M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
// ++u;
// ++v;
dinic.addEdge(u, v, w);
}
ValueVector V(N);
std::iota(V.begin(), V.end(), 1);
PairMatrix G(N + 1);
solve(V, G, dinic);
ValueMatrix dist(N + 1, ValueVector(N + 1, std::numeric_limits<valueType>::max()));
for (valueType i = 1; i <= N; ++i) {
dfs(i, 0, G, dist[i]);
dist[i][i] = 0;
}
{
valueType sum = 0;
for (valueType i = 1; i <= N; ++i)
for (valueType j = 1; j < i; ++j)
sum += dist[i][j];
std::cerr << sum << std::endl;
}
valueType Q;
std::cin >> Q;
for (valueType q = 0; q < Q; ++q) {
valueType u, v;
std::cin >> u >> v;
// ++u;
// ++v;
std::cout << dist[u][v] << '\n';
}
std::cout << std::flush;
return 0;
}
[CQOI2016] 不同的最小割
建出最小割树后将所有点对的最小割去重即可。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
class Dinic {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
valueType N;
Graph G;
ValueVector depth;
IterVector start;
bool Initialized;
public:
explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType x, valueType y, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[x].emplace_back(y, cap);
G[y].emplace_back(x, cap);
G[x].back().pair = std::prev(G[y].end());
G[y].back().pair = std::prev(G[x].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
return result;
}
bool reachable(valueType n) const {
return depth[n] > 0;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &e = Begin[u]; e != G[u].end(); ++e) {
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
};
void solve(ValueVector const &V, PairMatrix &G, Dinic &dinic) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
G[S].emplace_back(T, weight);
G[T].emplace_back(S, weight);
ValueVector A, B;
for (auto const &iter : V) {
if (dinic.reachable(iter))
A.emplace_back(iter);
else
B.emplace_back(iter);
}
solve(A, G, dinic);
solve(B, G, dinic);
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &dist) {
for (auto const &[to, weight] : G[x]) {
if (to == from)
continue;
dist[to] = std::min(dist[x], weight);
dfs(to, x, G, dist);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
Dinic dinic(N);
for (valueType i = 0; i < M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
dinic.addEdge(u, v, w);
}
ValueVector V(N);
std::iota(V.begin(), V.end(), 1);
PairMatrix G(N + 1);
solve(V, G, dinic);
ValueMatrix dist(N + 1, ValueVector(N + 1, std::numeric_limits<valueType>::max()));
for (valueType i = 1; i <= N; ++i) {
dfs(i, 0, G, dist[i]);
dist[i][i] = 0;
}
ValueVector pool;
pool.reserve(N * (N - 1) / 2);
for (valueType i = 1; i <= N; ++i)
for (valueType j = 1; j < i; ++j)
pool.emplace_back(dist[i][j]);
std::sort(pool.begin(), pool.end());
pool.erase(std::unique(pool.begin(), pool.end()), pool.end());
std::cout << pool.size() << std::endl;
return 0;
}
[ZJOI2011] 最小割
注意在两组测试数据之间需要输出一行空行。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
class Dinic {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
valueType N;
Graph G;
ValueVector depth;
IterVector start;
bool Initialized;
public:
explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType x, valueType y, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[x].emplace_back(y, cap);
G[y].emplace_back(x, cap);
G[x].back().pair = std::prev(G[y].end());
G[y].back().pair = std::prev(G[x].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
return result;
}
bool reachable(valueType n) const {
return depth[n] > 0;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &e = Begin[u]; e != G[u].end(); ++e) {
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
// e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
};
void solve(ValueVector const &V, PairMatrix &G, Dinic &dinic) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
G[S].emplace_back(T, weight);
G[T].emplace_back(S, weight);
ValueVector A, B;
for (auto const &iter : V) {
if (dinic.reachable(iter))
A.emplace_back(iter);
else
B.emplace_back(iter);
}
solve(A, G, dinic);
solve(B, G, dinic);
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &dist) {
for (auto const &[to, weight] : G[x]) {
if (to == from)
continue;
dist[to] = std::min(dist[x], weight);
dfs(to, x, G, dist);
}
}
void solve() {
valueType N, M;
std::cin >> N >> M;
Dinic dinic(N);
for (valueType i = 0; i < M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
dinic.addEdge(u, v, w);
}
ValueVector V(N);
std::iota(V.begin(), V.end(), 1);
PairMatrix G(N + 1);
solve(V, G, dinic);
ValueMatrix dist(N + 1, ValueVector(N + 1, std::numeric_limits<valueType>::max()));
for (valueType i = 1; i <= N; ++i) {
dfs(i, 0, G, dist[i]);
dist[i][i] = 0;
}
ValueVector pool;
pool.reserve(N * (N - 1) / 2);
for (valueType i = 1; i <= N; ++i)
for (valueType j = 1; j < i; ++j)
pool.emplace_back(dist[i][j]);
std::sort(pool.begin(), pool.end());
valueType Q;
std::cin >> Q;
for (valueType q = 0 ; q < Q; ++q) {
valueType x;
std::cin >> x;
std::cout << std::distance(pool.begin(), std::upper_bound(pool.begin(), pool.end(), x)) << '\n';
}
std::cout << std::endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType T;
std::cin >> T;
for (valueType i = 0; i < T; ++i)
solve();
std::cout << std::flush;
return 0;
}
[CERC2015] Juice Junctions
因为最大流的值等于最小割的值,因此建最小割树求出所有点对间的最小割即可。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
class Dinic {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
valueType N;
Graph G;
ValueVector depth;
IterVector start;
bool Initialized;
public:
explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType x, valueType y, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[x].emplace_back(y, cap);
G[y].emplace_back(x, cap);
G[x].back().pair = std::prev(G[y].end());
G[y].back().pair = std::prev(G[x].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
return result;
}
bool reachable(valueType n) const {
return depth[n] > 0;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &e = Begin[u]; e != G[u].end(); ++e) {
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
};
void solve(ValueVector const &V, PairMatrix &G, Dinic &dinic) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
G[S].emplace_back(T, weight);
G[T].emplace_back(S, weight);
ValueVector A, B;
for (auto const &iter : V) {
if (dinic.reachable(iter))
A.emplace_back(iter);
else
B.emplace_back(iter);
}
solve(A, G, dinic);
solve(B, G, dinic);
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &dist) {
for (auto const &[to, weight] : G[x]) {
if (to == from)
continue;
dist[to] = std::min(dist[x], weight);
dfs(to, x, G, dist);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
Dinic dinic(N);
for (valueType i = 0; i < M; ++i) {
valueType u, v;
std::cin >> u >> v;
dinic.addEdge(u, v, 1);
}
ValueVector V(N);
std::iota(V.begin(), V.end(), 1);
PairMatrix G(N + 1);
solve(V, G, dinic);
ValueMatrix dist(N + 1, ValueVector(N + 1, std::numeric_limits<valueType>::max()));
for (valueType i = 1; i <= N; ++i) {
dfs(i, 0, G, dist[i]);
dist[i][i] = 0;
}
ValueVector pool;
pool.reserve(N * (N - 1) / 2);
for (valueType i = 1; i <= N; ++i)
for (valueType j = 1; j < i; ++j)
pool.emplace_back(dist[i][j]);
std::cout << std::accumulate(pool.begin(), pool.end(), (valueType) 0) << std::endl;
return 0;
}
UVA11594 All Pairs Maximum Flow
注意 \(\tt{UVA}\) 要求输出内容中不含有多余的空格和空行。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
class Dinic {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), pair(){};
Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
valueType N;
Graph G;
ValueVector depth;
IterVector start;
bool Initialized;
public:
explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType x, valueType y, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[x].emplace_back(y, cap);
G[y].emplace_back(x, cap);
G[x].back().pair = std::prev(G[y].end());
G[y].back().pair = std::prev(G[x].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: init twice");
Initialized = true;
std::fill(depth.begin(), depth.end(), 0);
for (valueType i = 1; i <= N; ++i)
start[i] = G[i].begin();
}
void reset() {
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(depth.begin(), depth.end(), 0);
Initialized = false;
}
valueType maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("Dinic: maxFlow before init");
valueType result = 0;
while (bfs(S, T)) {
IterVector begin = start;
result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
}
return result;
}
bool reachable(valueType n) const {
return depth[n] > 0;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(depth.begin(), depth.end(), 0);
std::queue<valueType> Q;
Q.push(S);
depth[S] = 1;
while (!Q.empty()) {
valueType const u = Q.front();
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (!depth[e.to])) {
depth[e.to] = depth[u] + 1;
Q.push(e.to);
}
}
}
return depth[T] > 0;
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
for (auto &e = Begin[u]; e != G[u].end(); ++e) {
if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow)
return flow;
}
}
return result;
}
};
void solve(ValueVector const &V, PairMatrix &G, Dinic &dinic) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
G[S].emplace_back(T, weight);
G[T].emplace_back(S, weight);
ValueVector A, B;
for (auto const &iter : V) {
if (dinic.reachable(iter))
A.emplace_back(iter);
else
B.emplace_back(iter);
}
solve(A, G, dinic);
solve(B, G, dinic);
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &dist) {
for (auto const &[to, weight] : G[x]) {
if (to == from)
continue;
dist[to] = std::min(dist[x], weight);
dfs(to, x, G, dist);
}
}
void solve(valueType id) {
valueType N;
std::cin >> N;
Dinic dinic(N);
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= N; ++j) {
valueType w;
std::cin >> w;
if (w != 0 && i > j)
dinic.addEdge(i, j, w);
}
}
ValueVector V(N);
std::iota(V.begin(), V.end(), 1);
PairMatrix G(N + 1);
solve(V, G, dinic);
ValueMatrix dist(N + 1, ValueVector(N + 1, std::numeric_limits<valueType>::max()));
for (valueType i = 1; i <= N; ++i) {
dfs(i, 0, G, dist[i]);
dist[i][i] = 0;
}
std::cout << "Case #" << id << ":" << std::endl;
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= N; ++j)
std::cout << dist[i][j] << " \n"[j == N];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType T;
std::cin >> T;
for (valueType i = 1; i <= T; ++i)
solve(i);
std::cout << std::flush;
return 0;
}