Solution
可以利用网络流对“斥”的求解
先假设所有点都选,不选某些点可以使选择的方案合法,求出这些不选的点的价值总和的最小值
最小值联想到最小割
根据(横坐标+纵坐标)的奇偶性将图分成两部分
在不能同时选的点间连边(方向偶-奇),由于“割”时不能割掉点之间不能同时选的关系,所以它的流量应为正无穷
再从起点向偶部的每个点连一条流量为这个点的价值的边,从奇部的每个点向终点连一条流量为这个点的价值的边,
表示不选它失去的价值
跑最大流(即最小割)
Code
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e4+10,M=1e5;
int head[N],nxt[M],ver[M],edge[M],tot=1;
int s,t,n,m,d[N],x,maxflow,flow,sum,inf=1<<30;
int id(int x,int y)
{
return (x-1)*m+y;
}
void add(int u,int v,int w)
{
ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,head[u]=tot;
ver[++tot]=u,nxt[tot]=head[v],edge[tot]=0,head[v]=tot;
}
int bfs()
{
queue <int> q;
memset(d,0,sizeof(d));
d[s]=1,q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x],y;i;i=nxt[i])
if(edge[i]>0 && !d[y=ver[i]])
{
d[y]=d[x]+1;
q.push(y);
if(y==t) return 1;
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t) return flow;
int rest=flow;
for(int i=head[x],y;i && rest;i=nxt[i])
if(edge[i]>0 && d[y=ver[i]]==d[x]+1)
{
int k=dinic(y,min(edge[i],rest));
if(!k) d[y]=0;
edge[i]-=k,edge[i^1]+=k;
rest-=k;
}
return flow-rest;
}
int main()
{
scanf("%d%d",&n,&m);
s=0,t=n*m+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
sum+=x;
if((i+j)%2)
{
add(id(i,j),t,x);
continue;
}
add(s,id(i,j),x);
if(i>1) add(id(i,j),id(i-1,j),inf);
if(i<n) add(id(i,j),id(i+1,j),inf);
if(j>1) add(id(i,j),id(i,j-1),inf);
if(j<m) add(id(i,j),id(i,j+1),inf);
}
while(bfs()) while(flow=dinic(s,1<<30)) maxflow+=flow;
printf("%d\n",sum-maxflow);
return 0;
}
来源:https://www.cnblogs.com/hsez-cyx/p/12407490.html