【题解】方格取数问题(网络流)

方格取数问题

考虑这个要求"没有共同边",像极了最小割。

最小割:将图依照\(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;
}

posted @ 2019-07-23 21:34  谁是鸽王  阅读(215)  评论(0编辑  收藏  举报