[BZOJ 1834][ZJOI 2010] 网络扩容

题目大意

给定一张有向图,每条边都有一个容量 \(c\) 和一个扩容费用 \(w\)。这里扩容费用是指将容量扩大 \(1\) 所需的费用。求:

  • 在不扩容的情况下,\(1\)\(n\) 的最大流
  • \(1\)\(n\) 的最大流增加 \(k\) 所需的最小扩容费用。

\(1 \leqslant n \leqslant 1,000\)

\(1 \leqslant m \leqslant 5,000\)

\(1 \leqslant k \leqslant 10\)

题目链接

BZOJ 1834

CodeVS 1362

题解

第一问直接跑最大流。

第二问,对于每条边,再连一条费用为 \(w\)、容量无限的边表示扩容,最后从源点向 \(1\) 连一条容量为 \(k\) 的边限制容量。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <cstdio>
#include <climits>
#include <queue>
#include <algorithm>
const int MAXN = 1005;
const int MAXM = 5005;
struct Edge;
struct Node {
Edge *e, *curr, *pre;
int level, flow, dist;
bool inq;
} N[MAXN];
struct Edge {
Node *u, *v;
Edge *next, *rev;
int cap, flow, cost;
Edge(Node *u, Node *v, int cap, int cost) : u(u), v(v), cap(cap), flow(0), cost(cost), next(u->e) {}
};
void addEdge(int u, int v, int cap, int cost) {
N[u].e = new Edge(&N[u], &N[v], cap, cost);
N[v].e = new Edge(&N[v], &N[u], 0, -cost);
N[u].e->rev = N[v].e;
N[v].e->rev = N[u].e;
}
namespace Dinic {
bool makeLevelGraph(Node *s, Node *t, int n) {
for (int i = 1; i <= n; i++) N[i].level = 0;
std::queue<Node *> q;
q.push(s);
s->level = 1;
while (!q.empty()) {
Node *u = q.front();
q.pop();
for (Edge *e = u->e; e; e = e->next) {
if (e->cap > e->flow && e->v->level == 0) {
e->v->level = u->level + 1;
if (e->v == t) return true;
q.push(e->v);
}
}
}
return false;
}
int findPath(Node *s, Node *t, int limit = INT_MAX) {
if (s == t) return limit;
for (Edge *&e = s->curr; e; e = e->next) {
if (e->cap > e->flow && e->v->level == s->level + 1) {
int flow = findPath(e->v, t, std::min(limit, e->cap - e->flow));
if (flow > 0) {
e->flow += flow;
e->rev->flow -= flow;
return flow;
}
}
}
return 0;
}
int solve(int s, int t, int n) {
int res = 0;
while (makeLevelGraph(&N[s], &N[t], n)) {
for (int i = 1; i <= n; i++) N[i].curr = N[i].e;
int flow;
while ((flow = findPath(&N[s], &N[t])) > 0) res += flow;
}
return res;
}
}
namespace EdmondsKarp {
void solve(int s, int t, int n, int &flow, int &cost) {
flow = cost = 0;
while (true) {
for (int i = 0; i < n; i++) {
N[i].dist = INT_MAX;
N[i].flow = 0;
N[i].pre = NULL;
N[i].inq = false;
}
std::queue<Node *> q;
q.push(&N[s]);
N[s].dist = 0;
N[s].flow = INT_MAX;
while (!q.empty()) {
Node *u = q.front();
q.pop();
u->inq = false;
for (Edge *e = u->e; e; e = e->next) {
if (e->cap > e->flow && e->v->dist > u->dist + e->cost) {
e->v->dist = u->dist + e->cost;
e->v->flow = std::min(u->flow, e->cap - e->flow);
e->v->pre = e;
if (!e->v->inq) {
e->v->inq = true;
q.push(e->v);
}
}
}
}
if (N[t].dist == INT_MAX) break;
for (Edge *e = N[t].pre; e; e = e->u->pre) {
e->flow += N[t].flow;
e->rev->flow -= N[t].flow;
}
flow += N[t].flow;
cost += N[t].dist * N[t].flow;
}
}
}
struct Pair {
int u, v, cap, cost;
} E[MAXM];
int main() {
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
for (int i = 0; i < m; i++) {
scanf("%d %d %d %d", &E[i].u, &E[i].v, &E[i].cap, &E[i].cost);
addEdge(E[i].u, E[i].v, E[i].cap, 0);
}
int maxFlow = Dinic::solve(1, n, n);
for (int i = 0; i < m; i++) addEdge(E[i].u, E[i].v, INT_MAX, E[i].cost);
addEdge(0, 1, k, 0);
int flow, cost;
EdmondsKarp::solve(0, n, n + 1, flow, cost);
printf("%d %d\n", maxFlow, cost);
return 0;
}