zoukankan      html  css  js  c++  java
  • codevs 1907 方格取数 3

    Description

    在一个有m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。

    Input

    第1 行有2 个正整数m和n,分别表示棋盘的行数和列数。接下来的m行,每行有n个正整数,表示棋盘方格中的数。

    Output

    对于给定的方格棋盘,按照取数要求编程找出总和最大的数,将取数的最大总和输出。

    Sample Input

    3 3
    1 2 3
    3 2 3
    2 3 1 

    Sample Output

    11

    HINT

    n,m<=30

      嗯......这道题大概算是自己想出来的第一道网络流的题吧?

      虽然想了很久,WA了很多发,但终于A掉了......

      网络流的题真是难想(但这一题还是比较简单的),如果不是我已经知道这道题要用网络流做,还不知道要想到什么时候去了......

      好了,不扯多了,进正题:

      首先,我们发现直接建模的话非常不好搞,体重的条件不好表示......

      于是,我们就想,是否可以把我们选完数之后剩下的数给表示出来呢?我们发现这个不难做到。只需将棋盘黑白二染色,把黑点、白点各看成一块,相邻的格子间有边相连,不难发现将黑白两块分开的割的方案就是不选的点的合法方案(脑补一下应该可以搞出来)。所以最小割即是合法方案中选出的点和最大的方案。于是我们可以从源点向所有黑(白)点连一条容量为这个格子里的数的边,从黑(白)点向相邻的点连一条容量为INF的边,再从白(黑)点向汇点连一条容量为当前格子里的数的边,跑一边最大流即可得出不选的点的最小和,用所有数字之和减去它就是答案。

      update:其实这就是最大独立集等于总点数减去最大匹配数

      下面贴代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define maxm 100010
     7 #define INF (1<<25)
     8 #define r(j) (j^1)
     9 
    10 using namespace std;
    11 typedef long long llg;
    12 
    13 int head[101*101],next[maxm],to[maxm],c[maxm],tt=1;
    14 int a[101][101],zx[4]={0,0,1,-1},zy[4]={1,-1,0,0};
    15 int d[maxm],l,r,dep[maxm],ans,tut,s,t,n,m;
    16 
    17 int getint(){
    18     int w=0;bool q=0;
    19     char c=getchar();
    20     while((c>'9'||c<'0')&&c!='-') c=getchar();
    21     if(c=='-') q=1,c=getchar();
    22     while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    23     return q?-w:w;
    24 }
    25 
    26 void link(int x,int y,int z){
    27     to[++tt]=y;next[tt]=head[x];head[x]=tt;
    28     to[++tt]=x;next[tt]=head[y];head[y]=tt;
    29     c[tt^1]=z;
    30 }
    31 
    32 bool bfs(){
    33     for(int i=1;i<=t;i++) dep[i]=0;
    34     l=r=0;d[r++]=s;dep[s]=1;int u;
    35     while(l!=r){
    36         u=d[l++];
    37         for(int i=head[u];i;i=next[i])
    38             if(!dep[to[i]] && c[i]>0){
    39                 dep[to[i]]=dep[u]+1;
    40                 d[r++]=to[i];
    41             }
    42     }
    43     return dep[t]>0;
    44 }
    45 
    46 int dfs(int u,int low){
    47     int res=0,v;
    48     if(u==t) return low;
    49     if(!low) return 0;
    50     for(int i=head[u];i;i=next[i])
    51         if(c[i]>0 && dep[to[i]]==dep[u]+1){
    52             v=dfs(to[i],min(low-res,c[i]));
    53             c[i]-=v;c[r(i)]+=v;res+=v;
    54         }
    55     return res;
    56 }
    57 
    58 int main(){
    59     freopen("a.in","r",stdin);
    60     freopen("a.out","w",stdout);
    61     n=getint();m=getint();s=n*m+1;t=s+1;
    62     for(int i=1;i<=n;i++)
    63         for(int j=1;j<=m;j++)
    64             a[i][j]=getint();
    65     for(int i=1,now(0);i<=n;i++)
    66         for(int j=1;j<=m;j++){
    67             now++;
    68             if(!((i+j)&1)){
    69                 link(s,now,a[i][j]);
    70                 for(int k=0,x,y,n1;k<4;k++){
    71                     x=i+zx[k];y=j+zy[k];
    72                     if(x>0 && x<=n && y>0 && y<=m){
    73                         n1=(x-1)*m+y;
    74                         link(now,n1,INF);
    75                     }
    76                 }
    77             }
    78             else link(now,t,a[i][j]);
    79             tut+=a[i][j];
    80         }
    81     while(bfs())
    82         while(int tot=dfs(s,INF)) ans+=tot;
    83     printf("%d
    ",tut-ans);
    84     return 0;
    85 }
  • 相关阅读:
    从零开始写自己的PHP框架系列教程[前言]
    从零开始写自己的PHP框架系列教程(二)[App.php]
    Nginx
    常见的CSS
    常用JS代码
    jq常用
    EMMET 的HTM自动生成
    JS的小判断
    ARM寄存器与ATPCS/AAPCS
    关于笔记本电脑随想
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/5551356.html
Copyright © 2011-2022 走看看