Solution Set【2023.12.6】
CF343E Pumping Stations
首先建出最小割树。
现在问题转化为了求一个排列 \(p\),最大化 \(\sum \operatorname{dist}(p_i, p_{i + 1})\),其中 \(\operatorname{dist}(u, v)\) 表示路径 \(u \rightarrow v\) 上的最小边权。
考虑最小的一个边,发现若经过其的次数超过 \(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;
typedef std::vector<bool> bitset;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
constexpr valueType INF = std::numeric_limits<valueType>::max();
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, valueType &sum) {
if (V.size() < 2)
return;
valueType const S = V.front(), T = V.back();
dinic.reset();
dinic.init();
valueType const weight = dinic.maxFlow(S, T);
std::cerr << S << ' ' << T << ' ' << weight << std::endl;
sum += weight;
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, sum);
solve(B, G, dinic, sum);
}
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 dfs(valueType x, valueType from, PairMatrix const &G, bitset const &tag, ValueTuple &min) {
for (auto const &[to, weight] : G[x]) {
if (to == from || !tag[to])
continue;
min = std::min(min, std::make_tuple(weight, x, to));
dfs(to, x, G, tag, min);
}
}
void dfs(valueType x, valueType from, PairMatrix const &G, ValueVector &V, bitset const &tag) {
V.emplace_back(x);
for (auto const &[to, weight] : G[x]) {
if (to == from || !tag[to])
continue;
dfs(to, x, G, V, tag);
}
}
void divide(ValueVector const &V, valueType const &N, PairMatrix const &G) {
if (V.empty())
return;
valueType const S = V.front();
if (V.size() == 1) {
std::cout << S << ' ';
return;
}
bitset tag(N + 1, false);
for (auto const &iter : V)
tag[iter] = true;
ValueTuple min(INF, 0, 0);
dfs(S, -1, G, tag, min);
auto const &[w, u, v] = min;
ValueVector A, B;
dfs(u, v, G, A, tag);
dfs(v, u, G, B, tag);
divide(A, N, G);
divide(B, N, G);
}
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);
valueType sum = 0;
solve(V, G, dinic, sum);
std::cout << sum << std::endl;
divide(V, N, G);
std::cout << std::endl;
return 0;
}
[NOI2006] 最大获利
考虑将限制 \(\left(A_i, B_i, C_i\right)\) 解释为在满足建设 \(A_i\) 的前提上建设 \(B_i\) 可以得到 \(C_i\) 的价值。
考虑最小割,设 \(S\) 集合代表建设的基站,\(T\) 集合代表未建设的基站。
那么可以建边 \(A_i \rightarrow B_i\),容量为 \(C_i\)。考虑其前提条件,设 \(f_i = \sum_{\left(i, x, C\right)} C\),及所有以建设 \(i\) 为前提的限制的价值和,那么可以建边 \(S \rightarrow A\),容量为 \(f_A\)。
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
constexpr valueType INF = std::numeric_limits<valueType>::max();
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 from, valueType to, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[from].emplace_back(to, cap);
G[to].emplace_back(from, 0);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].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() {
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])
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;
}
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;
}
};
int main() {
valueType N, M;
std::cin >> N >> M;
valueType const total = N + 5;
valueType const S = N + 1, T = N + 2;
Dinic dinic(total);
for (valueType i = 1; i <= N; ++i) {
valueType w;
std::cin >> w;
dinic.addEdge(i, T, w);
}
valueType sum = 0;
ValueVector weight(N + 1, 0);
for (valueType i = 0; i < M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
if (w == 0)
continue;
sum += w;
dinic.addEdge(u, v, w);
weight[u] += w;
}
for (valueType i = 1; i <= N; ++i)
dinic.addEdge(S, i, weight[i]);
dinic.init();
valueType const ans = sum - dinic.maxFlow(S, T);
std::cout << ans << std::endl;
return 0;
}
[NOI2009] 植物大战僵尸
可以发现,我们可以将转化出若干形如
只要 \(\mathbf{A}\) 存活,那么 \(\mathbf{B}\) 一定存活
的限制。
考虑最小割,设 \(S\) 集合代表存活的植物,\(T\) 集合代表被击溃的植物。
那么对于所有的限制条件 \(\left(A, B\right)\),可以连边 \(A \rightarrow B\),容量为 \(\infty\)。
同时可以发现若上述的限制形成了环,那么在环中的任何植物均不会死亡,因此对于所有的限制关系进行一次拓扑排序即可,对于在环中的植物 \(\mathbf{X}\),建边 \(S \rightarrow X\),容量为 \(\infty\)。
下面考虑如何处理击溃植物的价值。
对于 \(\operatorname{Score} > 0\) 的植物 \(\mathbf{X}\),我们可以假设其已经被击溃,若其未被击溃,那么付出 \(\operatorname{Score}\) 的代价,因此有 \(\operatorname{Sum} \leftarrow \operatorname{Score}\),同时建边 \(X \rightarrow T\),容量为 \(\operatorname{Score}\)。
对于 \(\operatorname{Score} \le 0\) 的植物 \(\mathbf{X}\),若其被击溃,那么需要付出 \(\operatorname{Score}\) 的代价,因此建边 \(S \rightarrow X\),容量为 \(\left\lvert\operatorname{Score}\right\rvert\)。
最终的最大获利即为 \(\operatorname{Sum}\) 减去网络的最小割。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::queue<valueType> ValueQueue;
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 from, valueType to, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[from].emplace_back(to, cap);
G[to].emplace_back(from, 0);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].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() {
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])
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;
}
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;
}
};
constexpr valueType INF = std::numeric_limits<valueType>::max();
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
valueType size = 0;
valueType const S = ++size, T = ++size;
ValueMatrix id(N, ValueVector(M, 0));
for (valueType i = 0; i < N; ++i)
for (valueType j = 0; j < M; ++j)
id[i][j] = ++size;
Dinic dinic(size);
ValueMatrix G(size + 1);
ValueVector degree(size + 1, 0);
for (valueType i = 0; i < N; ++i) {
for (valueType j = 1; j < M; ++j) {
dinic.addEdge(id[i][j], id[i][j - 1], INF);
G[id[i][j]].emplace_back(id[i][j - 1]);
++degree[id[i][j - 1]];
}
}
valueType sum = 0;
for (valueType i = 0; i < N; ++i) {
for (valueType j = 0; j < M; ++j) {
valueType score, count;
std::cin >> score >> count;
if (score > 0) {
sum += score;
dinic.addEdge(id[i][j], T, score);
} else if (score < 0) {
dinic.addEdge(S, id[i][j], -score);
}
for (valueType k = 0; k < count; ++k) {
valueType x, y;
std::cin >> x >> y;
dinic.addEdge(id[i][j], id[x][y], INF);
G[id[i][j]].emplace_back(id[x][y]);
++degree[id[x][y]];
}
}
}
ValueQueue Q;
for (valueType i = 1; i <= size; ++i)
if (degree[i] == 0)
Q.push(i);
while (!Q.empty()) {
valueType const x = Q.front();
Q.pop();
for (auto const &iter : G[x])
if (--degree[iter] == 0)
Q.push(iter);
}
for (valueType i = 1; i <= size; ++i)
if (degree[i] != 0)
dinic.addEdge(S, i, INF);
dinic.init();
std::cout << (sum - dinic.maxFlow(S, T)) << std::endl;
return 0;
}
[六省联考 2017] 寿司餐厅
对于负贡献的处理可以参考 [NOI2009] 植物大战僵尸。
同时我们可以得出一些限制条件,比如若 \(d_{l, r}\) 产生贡献那么对于 \(l^{\prime} \le l \le r \le r^{\prime}\) 的全部 \(d_{l^{\prime}, r^{\prime}}\),连边即可。
对于代号的处理,首先若 \(d_{i, i}\) 产生贡献那么其会付出 \(a_i\) 的代价,对于每种代号开一个节点,其不产生贡献当且仅当所有满足代号为其的 \(i\) 均有 \(d_{i, i}\) 产生贡献。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
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 from, valueType to, valueType cap) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("Dinic: addEdge after init");
G[from].emplace_back(to, cap);
G[to].emplace_back(from, 0);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].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() {
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])
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;
}
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;
}
};
constexpr valueType INF = std::numeric_limits<valueType>::max();
constexpr valueType V = 1000;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
valueType size = 0;
valueType const S = ++size, T = ++size;
ValueMatrix id(N + 1, ValueVector(N + 1, 0));
for (valueType i = 1; i <= N; ++i)
for (valueType j = 1; j <= N; ++j)
id[i][j] = ++size;
ValueVector code(V + 1, 0);
for (valueType i = 1; i <= V; ++i)
code[i] = ++size;
Dinic dinic(size);
for (valueType i = 1; i <= V; ++i)
dinic.addEdge(code[i], T, i * i * M);
for (valueType i = 1; i <= N; ++i) {
valueType type;
std::cin >> type;
dinic.addEdge(id[i][i], T, type);
dinic.addEdge(id[i][i], code[type], INF);
}
valueType sum = 0;
for (valueType i = 1; i <= N; ++i) {
for (valueType j = i; j <= N; ++j) {
if (i < j) {
dinic.addEdge(id[i][j], id[i + 1][j], INF);
dinic.addEdge(id[i][j], id[i][j - 1], INF);
}
valueType weight;
std::cin >> weight;
if (weight > 0) {
sum += weight;
dinic.addEdge(S, id[i][j], weight);
} else if (weight < 0) {
dinic.addEdge(id[i][j], T, -weight);
}
}
}
dinic.init();
std::cout << (sum - dinic.maxFlow(S, T)) << std::endl;
return 0;
}
餐巾计划问题
可以发现每天需要处理旧餐巾并且创造出新的干净餐巾,因此考虑将这两部分拆分为两个节点 \(\operatorname{in}_i\) 和 \(\operatorname{out}_i\),其中 \(in_i\) 负责产生指定数量的餐巾并交付至 \(T\),\(\operatorname{out}_i\) 负责从 \(S\) 获取 \(\operatorname{in}_i\) 产生的餐巾并进行处理。
那么可以发现,\(\operatorname{in}_i\) 可以从如下三种来源获得餐巾:
- 从 \(S\) 直接购买
- 从 \(\operatorname{out}_{i - m}\) 花费 \(f\) 获取
- 从 \(\operatorname{out}_{i - n}\) 花费 \(s\) 获取
建出网络后的最小费用最大流即为答案。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
class MCMF {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
valueType cost;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), cost(0), pair(){};
Edge(valueType to, valueType cap, valueType c, iterator pair = iterator()) : to(to), cap(cap), flow(0), cost(c),
pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
typedef std::vector<bool> bitset;
valueType N;
Graph G;
ValueVector dist;
IterVector start;
bool Initialized;
public:
explicit MCMF(valueType N) : N(N), G(N + 1), dist(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType from, valueType to, valueType cap, valueType cost) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: addEdge after init");
G[from].emplace_back(to, cap, cost);
G[to].emplace_back(from, 0, -cost);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: init twice");
Initialized = true;
std::fill(dist.begin(), dist.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("MCMF: reset before init");
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(dist.begin(), dist.end(), 0);
Initialized = false;
}
std::pair<valueType, valueType> maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("MCMF: maxFlow before init");
std::pair<valueType, valueType> result(0, 0);
while (bfs(S, T)) {
IterVector begin = start;
bitset visited(N + 1, false);
valueType const flow = dfs(S, T, std::numeric_limits<valueType>::max(), begin, visited);
result.first += flow;
result.second += flow * dist[T];
}
return result;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(dist.begin(), dist.end(), std::numeric_limits<valueType>::max());
bitset visited(N + 1, false);
std::queue<valueType> Q;
Q.push(S);
dist[S] = 0;
visited[S] = true;
while (!Q.empty()) {
valueType const u = Q.front();
visited[u] = false;
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (dist[e.to] > dist[u] + e.cost)) {
dist[e.to] = dist[u] + e.cost;
if (!visited[e.to]) {
Q.push(e.to);
visited[e.to] = true;
}
}
}
}
return dist[T] != std::numeric_limits<valueType>::max();
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin, bitset &visited) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
visited[u] = true;
for (auto &e = Begin[u]; e != G[u].end() && flow > 0; ++e) {
if (!visited[e->to] && e->cap > e->flow && dist[e->to] == dist[u] + e->cost) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin, visited);
if (f == 0) {
dist[e->to] = std::numeric_limits<valueType>::max();
continue;
}
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow) {
visited[u] = false;
return flow;
}
}
}
visited[u] = false;
return result;
}
};
constexpr valueType INF = std::numeric_limits<valueType>::max();
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, p, m, f, n, s;
std::cin >> N;
ValueVector IN(N + 1, 0), OUT(N + 1, 0), R(N + 1);
for (valueType i = 1; i <= N; ++i)
std::cin >> R[i];
std::cin >> p >> m >> f >> n >> s;
valueType size = 0;
valueType const S = ++size, T = ++size;
for (valueType i = 1; i <= N; ++i)
IN[i] = ++size;
for (valueType i = 1; i <= N; ++i)
OUT[i] = ++size;
MCMF mcmf(size);
for (valueType i = 1; i <= N; ++i) {
mcmf.addEdge(S, IN[i], INF, p);
mcmf.addEdge(IN[i], T, R[i], 0);
mcmf.addEdge(S, OUT[i], R[i], 0);
}
for (valueType i = 1; i < N; ++i)
mcmf.addEdge(OUT[i], OUT[i + 1], INF, 0);
for (valueType i = m + 1; i <= N; ++i)
mcmf.addEdge(OUT[i - m], IN[i], INF, f);
for (valueType i = n + 1; i <= N; ++i)
mcmf.addEdge(OUT[i - n], IN[i], INF, s);
mcmf.init();
auto const result = mcmf.maxFlow(S, T);
std::cout << result.second << std::endl;
return 0;
}
80人环游世界
可以类比 餐巾计划问题 的处理方法将每个国家拆分为入境口和出境口。
需要注意的是在本题中所有国家的入境口从源点可获取最多共 \(M\) 个人。
故可以考虑新建一个节点 \(\operatorname{start}\),并建边 \(S \rightarrow \operatorname{start}\),容量为 \(M\),这样让各个入境点从 \(\operatorname{start}\) 获取人即可。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
class MCMF {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
valueType cost;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), cost(0), pair(){};
Edge(valueType to, valueType cap, valueType c, iterator pair = iterator()) : to(to), cap(cap), flow(0), cost(c),
pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
typedef std::vector<bool> bitset;
valueType N;
Graph G;
ValueVector dist;
IterVector start;
bool Initialized;
public:
explicit MCMF(valueType N) : N(N), G(N + 1), dist(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType from, valueType to, valueType cap, valueType cost) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: addEdge after init");
G[from].emplace_back(to, cap, cost);
G[to].emplace_back(from, 0, -cost);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: init twice");
Initialized = true;
std::fill(dist.begin(), dist.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("MCMF: reset before init");
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(dist.begin(), dist.end(), 0);
Initialized = false;
}
std::pair<valueType, valueType> maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("MCMF: maxFlow before init");
std::pair<valueType, valueType> result(0, 0);
while (bfs(S, T)) {
IterVector begin = start;
bitset visited(N + 1, false);
valueType const flow = dfs(S, T, std::numeric_limits<valueType>::max(), begin, visited);
result.first += flow;
result.second += flow * dist[T];
}
return result;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(dist.begin(), dist.end(), std::numeric_limits<valueType>::max());
bitset visited(N + 1, false);
std::queue<valueType> Q;
Q.push(S);
dist[S] = 0;
visited[S] = true;
while (!Q.empty()) {
valueType const u = Q.front();
visited[u] = false;
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (dist[e.to] > dist[u] + e.cost)) {
dist[e.to] = dist[u] + e.cost;
if (!visited[e.to]) {
Q.push(e.to);
visited[e.to] = true;
}
}
}
}
return dist[T] != std::numeric_limits<valueType>::max();
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin, bitset &visited) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
visited[u] = true;
for (auto &e = Begin[u]; e != G[u].end() && flow > 0; ++e) {
if (!visited[e->to] && e->cap > e->flow && dist[e->to] == dist[u] + e->cost) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin, visited);
if (f == 0) {
dist[e->to] = std::numeric_limits<valueType>::max();
continue;
}
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow) {
visited[u] = false;
return flow;
}
}
}
visited[u] = false;
return result;
}
};
constexpr valueType INF = std::numeric_limits<valueType>::max();
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
ValueVector IN(N + 1, 0), OUT(N + 1, 0);
valueType size = 0;
valueType const S = ++size, T = ++size, start = ++size;
for (valueType i = 1; i <= N; ++i)
IN[i] = ++size;
for (valueType i = 1; i <= N; ++i)
OUT[i] = ++size;
MCMF mcmf(size);
mcmf.addEdge(S, start, M, 0);
for (valueType i = 1; i <= N; ++i) {
valueType count;
std::cin >> count;
mcmf.addEdge(start, IN[i], INF, 0);
mcmf.addEdge(IN[i], T, count, 0);
mcmf.addEdge(S, OUT[i], count, 0);
}
for (valueType i = 1; i <= N; ++i) {
for (valueType j = i + 1; j <= N; ++j) {
valueType weight;
std::cin >> weight;
if (weight == -1)
continue;
mcmf.addEdge(OUT[i], IN[j], INF, weight);
}
}
mcmf.init();
auto const result = mcmf.maxFlow(S, T);
std::cout << result.second << std::endl;
return 0;
}
[SDOI2010] 星际竞速
可以类比 餐巾计划问题 的处理方法将每颗行星拆分为入口和出口。
由于访问每个行星恰好一次,所以我们可以不花费任何代价的从源点到达任何行星一次,之后正常处理题目的边即可。
Code
#include <bits/stdc++.h>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
class MCMF {
private:
struct Edge {
public:
typedef std::list<Edge> container;
typedef container::iterator iterator;
valueType to;
valueType cap;
valueType flow;
valueType cost;
iterator pair;
Edge() : to(-1), cap(-1), flow(-1), cost(0), pair(){};
Edge(valueType to, valueType cap, valueType c, iterator pair = iterator()) : to(to), cap(cap), flow(0), cost(c),
pair(pair){};
};
typedef std::vector<Edge::container> Graph;
typedef std::vector<Edge::iterator> IterVector;
typedef std::vector<bool> bitset;
valueType N;
Graph G;
ValueVector dist;
IterVector start;
bool Initialized;
public:
explicit MCMF(valueType N) : N(N), G(N + 1), dist(N + 1, 0), start(N + 1), Initialized(false){};
void addEdge(valueType from, valueType to, valueType cap, valueType cost) {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: addEdge after init");
G[from].emplace_back(to, cap, cost);
G[to].emplace_back(from, 0, -cost);
G[from].back().pair = std::prev(G[to].end());
G[to].back().pair = std::prev(G[from].end());
}
void init() {
if (__builtin_expect(Initialized, false))
throw std::runtime_error("MCMF: init twice");
Initialized = true;
std::fill(dist.begin(), dist.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("MCMF: reset before init");
for (valueType i = 1; i <= N; ++i)
for (auto &iter : G[i])
iter.flow = 0;
std::fill(dist.begin(), dist.end(), 0);
Initialized = false;
}
std::pair<valueType, valueType> maxFlow(valueType S, valueType T) {
if (__builtin_expect(!Initialized, false))
throw std::runtime_error("MCMF: maxFlow before init");
std::pair<valueType, valueType> result(0, 0);
while (bfs(S, T)) {
IterVector begin = start;
bitset visited(N + 1, false);
valueType const flow = dfs(S, T, std::numeric_limits<valueType>::max(), begin, visited);
result.first += flow;
result.second += flow * dist[T];
}
return result;
}
private:
bool bfs(valueType S, valueType T) {
std::fill(dist.begin(), dist.end(), std::numeric_limits<valueType>::max());
bitset visited(N + 1, false);
std::queue<valueType> Q;
Q.push(S);
dist[S] = 0;
visited[S] = true;
while (!Q.empty()) {
valueType const u = Q.front();
visited[u] = false;
Q.pop();
for (auto const &e : G[u]) {
if ((e.cap > e.flow) && (dist[e.to] > dist[u] + e.cost)) {
dist[e.to] = dist[u] + e.cost;
if (!visited[e.to]) {
Q.push(e.to);
visited[e.to] = true;
}
}
}
}
return dist[T] != std::numeric_limits<valueType>::max();
}
valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin, bitset &visited) {
if (u == T || flow == 0)
return flow;
valueType result = 0;
visited[u] = true;
for (auto &e = Begin[u]; e != G[u].end() && flow > 0; ++e) {
if (!visited[e->to] && e->cap > e->flow && dist[e->to] == dist[u] + e->cost) {
valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin, visited);
if (f == 0) {
dist[e->to] = std::numeric_limits<valueType>::max();
continue;
}
e->flow += f;
e->pair->flow -= f;
result += f;
if (result == flow) {
visited[u] = false;
return flow;
}
}
}
visited[u] = false;
return result;
}
};
constexpr valueType INF = std::numeric_limits<valueType>::max();
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType N, M;
std::cin >> N >> M;
ValueVector IN(N + 1, 0), OUT(N + 1, 0);
valueType size = 0;
valueType const S = ++size, T = ++size;
for (valueType i = 1; i <= N; ++i)
IN[i] = ++size;
for (valueType i = 1; i <= N; ++i)
OUT[i] = ++size;
MCMF mcmf(size);
for (valueType i = 1; i <= N; ++i) {
valueType weight;
std::cin >> weight;
mcmf.addEdge(S, IN[i], INF, weight);
mcmf.addEdge(IN[i], T, 1, 0);
mcmf.addEdge(S, OUT[i], 1, 0);
}
for (valueType i = 0; i < M; ++i) {
valueType u, v, w;
std::cin >> u >> v >> w;
if (u > v)
std::swap(u, v);
mcmf.addEdge(OUT[u], IN[v], INF, w);
}
mcmf.init();
auto const result = mcmf.maxFlow(S, T);
std::cout << result.second << std::endl;
return 0;
}