洛谷 P2774 方格取数问题 最小割 -最大流
先染色成二分图
最大取和 = 最大和-最小舍弃和 = 最小割 二分图 : 最大点独立集 = 总权和 - 最小点覆盖集(最小割)
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 20000 + 10;
const int maxm = 1000000 + 10;
int n,m,k;
int l[maxn];//记录层数
int h[maxn];//链式前向星
int cur[maxn];
int tot = 0;
struct edge
{
int to;
int c;
int next;
edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
}es[maxm*2];//记录边 注意是2倍
void add_edge(int u, int v, int c)
{
es[tot] = edge(v,c,h[u]);
h[u] = tot++;
es[tot] = edge(u,0,h[v]);
h[v] = tot++;
// cout << u <<" " <<v << " " << c<<endl;
}
bool bfs(int s, int t)
{
memset(l,0,sizeof(l));
l[s] = 1;
queue <int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();
//cout << u <<endl;
q.pop();
if(u == t) return true;
for(int i = h[u]; i != -1; i = es[i].next)
{
int v = es[i].to;
if(!l[v] && es[i].c) {l[v] = l[u] + 1; q.push(v);}
}
}
return false;
}
int dfs(int x, int t, int mf)
{
if(x == t) return mf;
int ret = 0;
for(int &i = cur[x]; i != -1; i = es[i].next)
{
if(es[i].c && l[x] == l[es[i].to] - 1)
{
int f = dfs(es[i].to,t,min(es[i].c,mf - ret));
es[i].c -= f;
es[i^1].c += f;
ret += f;
if(ret == mf) return ret;
}
}
return ret;
}
int dinic(int s, int t)
{
int ans = 0;
while(bfs(s,t))
{
for(int i = 0; i <= t; i++) cur[i] = h[i];
ans += dfs(s,t,INF);
}
return ans;
}
int r,c;
int a[maxn][maxn];
bool check(int x, int y)
{
if(x < 1 || y < 1 || x > r || y > c) return false;
return true;
}
int fx[4] = {1,-1,0,0};
int fy[4] = {0,0,1,-1};
int main()
{
int ans = 0;
tot = 0;
memset(h,-1,sizeof(h));
scanf("%d%d",&r,&c);
for(int i = 1; i <= r; i++)
for(int j = 1; j <= c; j++)
{scanf("%d",&a[i][j]);ans += a[i][j];}
int s = 0,t = r*c+1;
for(int i = 1; i <= r; i++)
for(int j = 1; j <= c; j++)
if((i+j)%2==1)
add_edge((i-1)*c+j,t,a[i][j]);
else {
add_edge(s,(i-1)*c+j,a[i][j]);
for(int k = 0; k < 4; k++)
{
int fi = i+fx[k];
int fj = j+fy[k];
if(check(fi,fj)) add_edge((i-1)*c+j,(fi-1)*c+fj,INF);
}
}
int res = dinic(s,t);
ans -= res;
printf("%d\n",ans);
return 0;
}