zoukankan      html  css  js  c++  java
  • 【题解】方格取数问题(网络流)

    方格取数问题

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

    最小割:将图依照(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
    ",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
    ",sum-dinic());
          return 0;
    }
    
    
  • 相关阅读:
    【Winform】Find out the changed rows in DataGridView
    DataGridView merge colunm header
    Spread日付セールのカレンダーに本日を初期値として表示する
    JLPT
    sql server数据库是否区分大小写的设置
    IIS7に.NET Framework 4を登録する
    [翻译]使用ASP.NET AJAX让GridView的数据行显示提示框(ToolTip)
    SILVERLIGHT开始在整个网站积累更深入的体验(转载)
    net连接access数据库,输出结果到页面
    利用JavaScript实现简单的拖动层(只使用于IE)
  • 原文地址:https://www.cnblogs.com/winlere/p/11234629.html
Copyright © 2011-2022 走看看