Luogu_2774 方格取数问题
二分图最小割
第一次做这种题,对于某些强烈暗示性的条件并没有理解到。
也就是每一立刻理解到是这个图是二分图。
为什么?
横纵坐标为奇数的只会和横纵坐标为偶数的相连。
最大和=全局和-最小代价
所以可以反向缩小最小代价。
考虑奇数点与源点相连,偶数点与汇点相连,流量都是这个点的权值。
然后奇数点像偶数点连边,权值无限大。
这样构图。最小割是一个简单割。
割的流量就是最小的代价。
要么奇数点被割去,要么相邻的四个偶数点被割去
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using std::queue;
using std::min;
const int maxn=301;
const int inf=0x7fffffff;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
struct node
{
int p;
int nxt;
int value;
node(int a=0,int b=0,int c=0)
{
p=a;
value=b;
nxt=c;
}
};
node line[maxn*maxn<<1];
int head[maxn*maxn],tail;
int cur[maxn*maxn];
int Dis[maxn*maxn];
int Map[maxn][maxn];
int S,T;
void add(int a,int b,int c,int d)
{
line[++tail]=node(b,c,head[a]);
head[a]=tail;
line[++tail]=node(a,d,head[b]);
head[b]=tail;
}
void init(int n,int m)
{
S=n*m;T=n*m+1;
tail=-1;
memset(head,-1,sizeof(head));
}
int Bfs(int s,int t)
{
queue<int>q;
memset(Dis,0,sizeof(Dis));
Dis[s]=1;q.push(s);
while(!q.empty())
{
int pas=q.front();q.pop();
for(int i=head[pas];i!=-1;i=line[i].nxt)
{
int v=line[i].p;
if(Dis[v]||!line[i].value) continue;
Dis[v]=Dis[pas]+1;
q.push(v);
}
}
for(int i=0;i<=T;i++) cur[i]=head[i];
return Dis[t];
}
int Dfs(int now,int aim,int limte)
{
if(now==aim||!limte) return limte;
int res=0,f;
for(int &i=cur[now];i!=-1;i=line[i].nxt)
{
int v=line[i].p;
if(Dis[v]==Dis[now]+1&&(f=Dfs(v,aim,min(limte,line[i].value))))
{
res+=f;
limte-=f;
line[i].value-=f;
line[i^1].value+=f;
if(!limte) break;
}
}
return res;
}
int Dinic(int s,int t)
{
int res=0;
while(Bfs(s,t))
res+=Dfs(s,t,inf);
return res;
}
int main()
{
int n,m,tot=0;
scanf("%d%d",&n,&m);
init(n,m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&Map[i][j]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(((i+j)&1)==1)
{
add(S,i*m+j,Map[i][j],0);
for(int k=0;k<4;k++)
if(i+dx[k]>=0&&i+dx[k]<n&&j+dy[k]>=0&&j+dy[k]<m)
add(i*m+j,(i+dx[k])*m+(j+dy[k]),inf,0);
}
else
add(i*m+j,T,Map[i][j],0);
tot+=Map[i][j];
}
printf("%d",tot-Dinic(S,T));
return 0;
}