【题解】方格取数问题(网络流)
方格取数问题
考虑这个要求"没有共同边",像极了最小割。
最小割:将图依照\(S\)和\(T\)分为两个互无交集的集合,并且使得删去的元素(边)的权值和最小。
然后我们看看这个问题,先要分类以确定和\(S\)在一起和和\(T\)在一起的点。显然由于相邻点是对立的所以我们直接相邻的连\(inf\)边表示这个相邻关系无法被改变。这样这条边在最小割中就不会被鸽掉。
我们先对图进行黑白染色,相邻的黑白点之间连接\(inf\)边,我们能改变的状态是一个点在不在集合里面,所以我们让规定黑色连\(S\),白色连\(T\),边权就是点权,这个边代表这个点是否存在。现在要求相邻点不能同时存在且使代价最小,这样剩下的数最大,直接最小割即可。
说的很麻烦实际上就是
对图进行黑白染色,相邻的黑白点之间连接\(inf\)边,我们能改变的状态是一个点在不在集合里面,所以我们让规定黑色连\(S\),白色连\(T\),边权就是点权,跑最小割。
非此即彼的关系就是最小割啦
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e2+5;
int id[maxn][maxn];
int nodecnt;
int cnt(1),S,T;
struct E{
int to,nx,w;
E(){to=nx=w=0;}
E(const int&a,const int&b,const int&c){to=a;nx=b;w=c;}
}e[(maxn*maxn)<<4|1];
int head[maxn*maxn];
inline void add(const int&fr,const int&to,const int&w,const bool&f){
//printf("fr=%d to=%d w=%d f=%d\n",fr,to,w,f);
if(!(fr&&to))return;
e[++cnt]=E(to,head[fr],w);
head[fr]=cnt;
if(f)add(to,fr,0,0);
}
queue< int > q;
int d[maxn*maxn];
int cur[maxn*maxn],sum;
const int inf=0x3f3f3f3f;
inline bool bfs(){
for(register int t=1;t<=nodecnt;++t) d[t]=0,cur[t]=head[t];
q.push(S);
d[S]=1;
while(q.size()){
register int now=q.front();
q.pop();
for(register int t=head[now];t;t=e[t].nx){
if(e[t].w>0&&!d[e[t].to]){
d[e[t].to]=d[now]+1;
q.push(e[t].to);
}
}
}
return d[T];
}
int dfs(const int&now,int fl){
if(now==T||fl==0)return fl;
int ret=0;
for(register int &t=cur[now];t&&fl;t=e[t].nx){
if(d[e[t].to]==d[now]+1&&e[t].w>0){
int d=dfs(e[t].to,min(fl,e[t].w));
fl-=d;ret+=d;e[t].w-=d;e[t^1].w+=d;
}
}
return ret;
}
inline int dinic(){
int ret=0;
while(bfs())ret+=dfs(S,inf);
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
int n,m;
n=qr();m=qr();
for(register int t=1;t<=n;++t)
for(register int i=1;i<=m;++i)
id[t][i]=++nodecnt;
S=++nodecnt;T=++nodecnt;
for(register int t=1;t<=n;++t){
for(register int i=1,t1;i<=m;++i){
//cout<<((t&1)^(i^1)&1^1)<<' ';
sum+=(t1=qr());
if((t&1)^(i^1)&1)
add(id[t][i],T,t1,1);
if((t&1)^(i^1)&1^1){
add(S,id[t][i],t1,1);
add(id[t][i],id[t-1][i],inf,1);add(id[t][i],id[t+1][i],inf,1);
add(id[t][i],id[t][i+1],inf,1);add(id[t][i],id[t][i-1],inf,1);
}
}
}
printf("%d\n",sum-dinic());
return 0;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!