网络流边表存图的EK算法模版。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
//hdu1569
//最大点权独立集,求出最大流,然后用总和减去最大流
//主要是学习下最大流算法
//EK算法, 我们用边表存储图
const int inf = 10000000;
const int maxn = 20000;
const int maxm = 55;
struct node
{
int u, v;//左右端点
int f; //flow 流量
};
node e[maxn];
int map[maxm][maxm], first[2505], cc; //cc是结点编号
int next[maxn], p[2505], a[2505];
//加边
inline void add_edge(int u, int v, int f) //
{
//加入正向边
e[cc].u = u;
e[cc].v = v;
e[cc].f = f;
next[cc] = first[u];
first[u] = cc;
cc++;
//加入反向边
e[cc].u = v;
e[cc].v = u;
e[cc].f = 0; //是0
next[cc] = first[v];
first[v] = cc;
cc++;
}
//最大流的EK算法
int EK(int s, int t)
{
queue<int> q;
int f = 0; //结果
while(1)
{
memset(a, 0, sizeof(a));
memset(p, -1, sizeof(p));
q.push(s);
a[s] = inf;
while( !q.empty() )
{
int u = q.front();
q.pop();
int i;
for(i = first[u]; i != -1; i = next[i] )
{
if( !a[e[i].v] && e[i].f )
{
p[ e[i].v ] = i;
a[ e[i].v ] = min(a[u], e[i].f );
q.push(e[i].v);
}
}
}
if(a[t] == 0) break;
int u;
for(u = t; u != s; u = e[p[u]].u)
{
e[p[u]].f -= a[t];
e[p[u] ^ 1].f += a[t];
}
f += a[t];
}
return f;
}
int main()
{
int m,n;
while(scanf("%d%d",&m,&n)!=EOF)
{
int i, j, sum = 0;
cc = 0;
memset(first,-1,sizeof(first));
memset(next,-1,sizeof(next));
for(i=1; i<=m; i++)
for(j=1; j<=n; j++)
scanf("%d",&map[i][j]),sum+=map[i][j];
int s=0,t=n*m+1; //源点和汇点
for(i=1; i<=m; i++)
{
for(j=1; j<=n; j++)
{
int tmp=(i-1)*n+j; //计算点的编号
if((i+j)%2==0)
{
add_edge(s,tmp,map[i][j]);
//上下左右
if(i>1)
add_edge(tmp,(i-2)*n+j,inf);
if(i<m)
add_edge(tmp,i*n+j,inf);
if(j>1)
add_edge(tmp,(i-1)*n+j-1,inf);
if(j<n)
add_edge(tmp,(i-1)*n+j+1,inf);
}
else
add_edge(tmp,t,map[i][j]);
}
}
int ans=EK(s,t);
printf("%d\n",sum-ans);
}
return 0;
}