网络流之最小割问题

最小割问题

对于给定的网络流模型,其最小割是指删除边权和最小的边集,使得 sstt 不连通。

最小割等于最大流,因为增广路的流量限制是由这些权值的边,方案不一定唯一。

例题

洛谷P2774

P2774 方格取数问题

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
#include<bits/stdc++.h>
typedef int int32;
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n, m, s, t, edge[N], level[N], tmp[N], cnt, sum, ans, dx[] = { 0,0,1,-1 },
dy[] = { 1,-1,0,0 };
vector<pair<int, int>>nbr[N];
bool bfs()
{
memset(level, 0, sizeof level);
queue<int>q;
q.push(s);
level[s] = 1;
while (!q.empty())
{
int x = q.front();
q.pop();
tmp[x] = 0;
for (auto& nxt : nbr[x])
if (edge[nxt.second] && !level[nxt.first])
{
level[nxt.first] = level[x] + 1;
q.push(nxt.first);
if (nxt.first == t)
return true;
}
}
return false;
}
int dinic(int x, int flow)
{
if (x == t)
return flow;
int rest = flow;
for (int i = tmp[x]; i < nbr[x].size(); i++)
{
tmp[x]++;
auto& nxt = nbr[x][i];
if (edge[nxt.second] && level[nxt.first] == level[x] + 1)
{
int inc = dinic(nxt.first, min(rest, edge[nxt.second]));
edge[nxt.second] -= inc;
edge[nxt.second ^ 1] += inc;
rest -= inc;
}
if (!rest)
break;
}
if (!(flow - rest))
level[x] = 0;
return flow - rest;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
s = cnt = 1, t = 2;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
int z;
cin >> z;
sum += z;
if ((i + j) & 1)
{
int x = s, y = (i - 1) * m + j + 2;
edge[++cnt] = z;
nbr[x].push_back({ y,cnt });
nbr[y].push_back({ x,++cnt });
}
else
{
int x = (i - 1) * m + j + 2, y = t;
edge[++cnt] = z;
nbr[x].push_back({ y,cnt });
nbr[y].push_back({ x,++cnt });
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if ((i + j) & 1)
for (int k = 0; k < 4; k++)
{
int nx = i + dx[k], ny = j + dy[k];
if (nx > 0 && ny > 0 && nx <= n && ny <= m)
{
int x = (i - 1) * m + j + 2, y = (nx - 1) * m + ny + 2, z = INT_MAX;
edge[++cnt] = z;
nbr[x].push_back({ y,cnt });
nbr[y].push_back({ x,++cnt });
}
}
while (bfs())
ans += dinic(s, INT_MAX);
cout << sum - ans;
return 0;
}