luogu P1935 [国家集训队]圈地计划 最小割
https://www.luogu.com.cn/blog/I-love-saber/solution-p1935
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010, M = 200010, INF = 1e8;
#define int long long
int n, m, S, T;
int c[200][200];
int h[N], e[M], w[M], ne[M], idx;
int q[N], d[N], cur[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}
bool bfs()
{
int hh = 0, tt = 0;
memset(d, -1, sizeof d);
q[0] = S, d[S] = 0, cur[S] = h[S];
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i])
{
int ver = e[i];
if (d[ver] == -1 && w[i])
{
d[ver] = d[t] + 1;
cur[ver] = h[ver];
if (ver == T) return true;
q[ ++ tt] = ver;
}
}
}
return false;
}
int find(int u, int limit)
{
if (u == T) return limit;
int flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i])
{
cur[u] = i; // 当前弧优化
int ver = e[i];
if (d[ver] == d[u] + 1 && w[i])
{
int t = find(ver, min(w[i], limit - flow));
if (!t) d[ver] = -1;
w[i] -= t, w[i ^ 1] += t, flow += t;
}
}
return flow;
}
int dinic()
{
int r = 0, flow;
while (bfs()) while (flow = find(S, INF)) r += flow;
return r;
}
int num(int a,int b)
{
return m*(a-1)+b;
}
signed main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
S=0,T=N-1;
int sum=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
int a;
cin>>a;
if ((i+j)&1)add(S,num(i,j),a);
else add(num(i,j),T,a);
sum+=a;
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
int a;
cin>>a;
if ((i+j)&1)add(num(i,j),T,a);
else add(S,num(i,j),a);
sum+=a;
}
}
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&c[i][j]);
int tx[]= {0,-1,0,1},ty[]= {1,0,-1,0};
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
for(int k=0; k<4; k++)
{
int xx=i+tx[k],yy=j+ty[k];
if (xx<=0||xx>n)continue;
if (yy<=0||yy>m)continue;
add(num(i,j),num(xx,yy),c[i][j]+c[xx][yy]);
sum+=c[i][j];
}
}
}
cout<<sum-dinic();
return 0;
}