给定这种形式的一个图,求其最大流。

题解

据 Hellc 说,直接 dinic 就可以了,但是我没写,认真学习了一下正解,「平面图最大流」。

论文东西太多了,我转述也转述不清,详情见 《两极相通 —— 浅析最大最小定理在信息学竞赛中的应用》,写的很好很形象。

代码

注意只有一行或者只有一列时的特判。

#include <cstdio>
#include <cstring>
#include <climits>
#include <queue>
#include <algorithm>
#include <functional>
const int MAX_N = 1000;
const int MAX_M = 1000;
const int MAX_NODE = MAX_N * MAX_M * 2 + 2;
struct Node;
struct Edge;
struct Node {
Edge *e;
int dist;
bool vis;
} N[MAX_NODE];
struct Edge {
Node *fr, *to;
Edge *ne;
int w;
Edge(Node *fr, Node *to, int w) : fr(fr), to(to), ne(fr->e), w(w) {}
};
inline void addEdge(int fr, int to, int w) {
N[fr].e = new Edge(&N[fr], &N[to], w);
N[to].e = new Edge(&N[to], &N[fr], w);
}
inline int djk(int begin, int end, int n) {
Node *s = &N[begin], *t = &N[end];
std::priority_queue< std::pair<int, Node *>, std::vector< std::pair<int, Node *> >, std::greater< std::pair<int, Node *> > > q;
for (int i = 0; i < n; i++) N[i].dist = INT_MAX, N[i].vis = false;
s->dist = 0;
q.push(std::make_pair(s->dist, s));
while (!q.empty()) {
Node *v = q.top().second;
q.pop();
if (v->vis) continue;
v->vis = true;
for (Edge *e = v->e; e; e = e->ne) {
if (e->to->dist > v->dist + e->w) {
e->to->dist = v->dist + e->w;
q.push(std::make_pair(e->to->dist, e->to));
}
}
}
return t->dist;
}
int n, m;
inline int id(int i, int j) {
return (i - 1) * 2 * (m - 1) + j;
}
inline int solve() {
if (n == 1 && m == 1) return 0;
else if (n == 1) {
int ans = INT_MAX;
for (int i = 0; i < m - 1; i++) {
int w;
scanf("%d", &w);
ans = std::min(ans, w);
}
return ans;
} else if (m == 1) {
int ans = INT_MAX;
for (int i = 0; i < n - 1; i++) {
int w;
scanf("%d", &w);
ans = std::min(ans, w);
}
return ans;
}
int s = 2 * (m - 1) * (n - 1), t = s + 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m - 1; j++) {
int w;
scanf("%d", &w);
if (i == 1) {
addEdge(id(i, (j * 2) ^ 1), t, w);
} else if (i == n) {
addEdge(s, id(i - 1, j * 2), w);
} else {
addEdge(id(i, (j * 2) ^ 1), id(i - 1, j * 2), w);
}
}
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
int w;
scanf("%d", &w);
if (j == 0) {
addEdge(s, id(i, j * 2), w);
} else if (j == m - 1) {
addEdge(id(i, ((j - 1) * 2) ^ 1), t, w);
} else {
addEdge(id(i, ((j - 1) * 2) ^ 1), id(i, (j * 2)), w);
}
}
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < m - 1; j++) {
int w;
scanf("%d", &w);
addEdge(id(i, j * 2), id(i, (j * 2) ^ 1), w);
}
}
return djk(s, t, t + 1);
}
int main() {
// freopen("bjrabbit.in", "r", stdin), freopen("bjrabbit.out", "w", stdout);
scanf("%d %d", &n, &m);
printf("%d\n", solve());
return 0;
}