题目大意:
有一个(m*n)的网格图,每个格子有一个权值,要求选了当前格子后不能选择与当前格子相邻的四个格子,求选择的最大权值和
最小割构造模型,又有点类似最大闭合权子图的思想
先将所有格子的权值加起来
然后将格子黑白染色,将黑色格子与(S)相连,白色格子与(T)相连,容量为点权。
然后将黑色能影响到的白色格子连一条(inf)边
根据最大闭合权子图的思想,答案即为总权值减去最小割
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int inf=0x7f7f7f7f;
int n,m,st,ed,ret,sum,tot;
int id[110][110];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
int head[10010],cur[10010],d[10010],cnt=1;
struct point
{
int nxt,to,val;
}a[200010];
inline void add(int x,int y,int z)
{
a[++cnt].nxt=head[x];
a[cnt].to=y;
a[cnt].val=z;
head[x]=cnt;
}
queue<int> q;
inline bool bfs()
{
for(int i=1;i<=n*m+2;++i)
{
cur[i]=head[i];
d[i]=0;
}
q.push(st);d[st]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=a[i].nxt)
{
int t=a[i].to;
if(!d[t]&&a[i].val)
{
d[t]=d[now]+1;
q.push(t);
}
}
}
return d[ed];
}
inline int dfs(int now,int c)
{
if(now==ed||!c) return c;
int ret=c,f;
for(int i=cur[now];i;i=a[i].nxt)
{
cur[now]=i;
int t=a[i].to;
if(d[t]==d[now]+1)
{
f=dfs(t,min(a[i].val,ret));
if(!f) continue;
a[i].val-=f;
a[i^1].val+=f;
ret-=f;
if(!ret) return c;
}
}
if(c==ret) d[now]=0;
return c-ret;
}
inline int dinic()
{
while(bfs()) ret+=dfs(st,inf);
return ret;
}
signed main()//最大独立点权集=最点权-最小点权覆盖(最小割)
{
n=read(),m=read();
st=n*m+1,ed=n*m+2;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
id[i][j]=++tot;
for(int x,i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
x=read();
sum+=x;
if(((i+j)&1)==1)//二分图染色,(i+j)&1==1为黑,源点连黑,汇点连白
{
add(st,id[i][j],x),add(id[i][j],st,0);
for(int k=0;k<4;++k)//黑向影响到的白连Inf边
{
int tx=i+dx[k],ty=j+dy[k];
add(id[i][j],id[tx][ty],inf);
add(id[tx][ty],id[i][j],0);
}
}
else add(id[i][j],ed,x),add(ed,id[i][j],0);
}
}
printf("%d
",sum-dinic());
return 0;
}