[CQOI 2015] 网络吞吐量

题目大意

给定一个有向图,起点为 11 号点,终点为 nn 号点,保证从起点能到达终点,但不存在边 1n1 \rightarrow n 。题目有两问:

  • 边权 dd 表示距离,求起点到终点的最短路。
  • 点权 cc 表示点的容量,起点与终点不计,求最大流。

1n5001 \leqslant n \leqslant 500

1m100,0001 \leqslant m \leqslant 100,000

1d,  c1,000,000,0001 \leqslant d,\; c\leqslant 1,000,000,000

题目链接

【CQOI 2015】网络吞吐量 - LibreOJ 2096

题解

第一问直接最短路。

第二问拆点求最大流,只保留在最短路上的边。

代码

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
#include <cstdio>
#include <climits>
#include <queue>
#include <algorithm>
const int MAXN = 505;
const int MAXM = 100005;
struct Edge;
struct Node {
Edge *e, *curr;
long long w;
bool vis;
} N[MAXN << 1];
struct Edge {
Node *u, *v;
Edge *next, *rev;
long long w, flow;
Edge(Node *u, Node *v, long long w) : u(u), v(v), w(w), flow(0), next(u->e) {}
};
void addEdge(int u, int v, long long w, bool di = false) {
N[u].e = new Edge(&N[u], &N[v], w);
N[v].e = new Edge(&N[v], &N[u], di ? w : 0);
N[u].e->rev = N[v].e;
N[v].e->rev = N[u].e;
}
namespace Dijkstra {
struct HeapNode {
Node *u;
int dist;
bool operator<(const HeapNode &another) const {
return dist > another.dist;
}
};
void dijkstra(Node *s) {
std::priority_queue<HeapNode> q;
q.push((HeapNode) {s, 0});
s->w = 0;
while (!q.empty()) {
Node *u = q.top().u;
q.pop();
if (u->vis) continue;
u->vis = true;
for (Edge *e = u->e; e; e = e->next) {
if (e->v->w > u->w + e->w) {
e->v->w = u->w + e->w;
q.push((HeapNode) {e->v, e->v->w});
}
}
}
}
void solve(int s, int n) {
for (int i = 1; i <= n; i++) N[i].w = LLONG_MAX;
dijkstra(&N[s]);
}
}
namespace Dinic {
bool makeLevelGraph(Node *s, Node *t, int n) {
for (int i = 1; i <= n; i++) N[i].w = 0;
std::queue<Node *> q;
q.push(s);
s->w = 1;
while (!q.empty()) {
Node *u = q.front();
q.pop();
for (Edge *e = u->e; e; e = e->next) {
if (e->w > e->flow && e->v->w == 0) {
e->v->w = u->w + 1;
if (e->v == t) return true;
q.push(e->v);
}
}
}
return false;
}
long long findPath(Node *s, Node *t, long long limit = LLONG_MAX) {
if (s == t) return limit;
for (Edge *&e = s->curr; e; e = e->next) {
if (e->w > e->flow && e->v->w == s->w + 1) {
int flow = findPath(e->v, t, std::min(limit, e->w - e->flow));
if (flow > 0) {
e->flow += flow;
e->rev->flow -= flow;
return flow;
}
}
}
return 0;
}
long long solve(int s, int t, int n) {
long long res = 0;
while (makeLevelGraph(&N[s], &N[t], n)) {
for (int i = 1; i <= n; i++) N[i].curr = N[i].e;
long long flow;
while ((flow = findPath(&N[s], &N[t])) > 0) res += flow;
}
return res;
}
}
void clear(int n) {
for (int i = 1; i <= n; i++) for (Edge *&e = N[i].e, *next; e; next = e->next, delete e, e = next);
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
static int E[MAXM][3];
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &E[i][0], &E[i][1], &E[i][2]);
addEdge(E[i][0], E[i][1], E[i][2], true);
}
Dijkstra::solve(1, n);
clear(n << 1);
for (int i = 0; i < m; i++) {
int u = E[i][0], v = E[i][1];
long long w = E[i][2];
if (N[u].w + w == N[v].w) addEdge(u + n, v, LLONG_MAX);
if (N[v].w + w == N[u].w) addEdge(v + n, u, LLONG_MAX);
}
for (int i = 1; i <= n; i++) {
int c;
scanf("%d", &c);
addEdge(i, i + n, i != 1 && i != n ? c : LLONG_MAX);
}
printf("%lld\n", Dinic::solve(1, n << 1, n << 1));
return 0;
}