Description

高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000

Sample Output

1210

【样例说明】

两人都选理,则获得100+110+1000的喜悦值。

【数据规模】

对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

HINT

Source

思路

这题面真难看。

(from 《浅析一类最小割问题(pty)》)

代码

#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>

const int maxn=100;
const int maxk=10000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;

int n,m;

struct network_flow
{
  int pre[maxm+10],now[maxk+10],son[maxm+10],val[maxm+10],tot;
  int d[maxk+10];

  inline int clear()
  {
    memset(now,0,sizeof now);
    tot=1;
    return 0;
  }

  inline int ins(int a,int b,int c)
  {
    pre[++tot]=now[a];
    now[a]=tot;
    son[tot]=b;
    val[tot]=c;
    return 0;
  }

  inline int add(int a,int b,int c)
  {
    ins(a,b,c);
    ins(b,a,0);
    return 0;
  }

  inline int bfs()
  {
    std::queue<int> q;
    q.push(0);
    memset(d,-1,sizeof d);
    d[0]=0;
    while(!q.empty())
      {
        int u=q.front(),j=now[u];
        q.pop();
        while(j)
          {
            int v=son[j];
            if(val[j]&&(d[v]==-1))
              {
                d[v]=d[u]+1;
                q.push(v);
                if(v==n*m+1)
                  {
                    return 1;
                  }
              }
            j=pre[j];
          }
      }
    return 0;
  }

  inline int dfs(int u,int flow)
  {
    if(u==n*m+1)
      {
        return flow;
      }
    int res=flow,j=now[u];
    while(j&&res)
      {
        int v=son[j];
        if(val[j]&&(d[v]==d[u]+1))
          {
            int f=dfs(v,std::min(res,val[j]));
            if(!f)
              {
                d[v]=-1;
              }
            val[j]-=f;
            val[j^1]+=f;
            res-=f;
          }
        j=pre[j];
      }
    return flow-res;
  }

  inline int dinic()
  {
    int ans=0;
    while(bfs())
      {
        ans+=dfs(0,inf);
      }
    return ans;
  }
};

network_flow w;
int s[maxn+10][maxn+10],t[maxn+10][maxn+10],ans;

int main()
{
  scanf("%d%d",&n,&m);
  w.clear();
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<=m; ++j)
        {
          scanf("%d",&t[i][j]);
          w.ins(n*m+1,(i-1)*m+j,0);
          w.ins((i-1)*m+j,n*m+1,t[i][j]<<1);
          ans+=t[i][j];
        }
    }
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<=m; ++j)
        {
          scanf("%d",&s[i][j]);
          w.ins((i-1)*m+j,0,0);
          w.ins(0,(i-1)*m+j,s[i][j]<<1);
          ans+=s[i][j];
        }
    }
  for(register int i=1; i<n; ++i)
    {
      for(register int j=1; j<=m; ++j)
        {
          scanf("%d",&t[i][j]);
        }
    }
  for(register int i=1; i<n; ++i)
    {
      for(register int j=1; j<=m; ++j)
        {
          scanf("%d",&s[i][j]);
        }
    }
  for(register int i=1; i<n; ++i)
    {
      for(register int j=1; j<=m; ++j)
        {
          int a=(i-1)*m+j,b=i*m+j,to=n*m+1;
          w.ins(0,a,s[i][j]);
          w.ins(a,0,0);
          w.ins(0,b,s[i][j]);
          w.ins(b,0,0);
          w.ins(a,to,t[i][j]);
          w.ins(to,a,0);
          w.ins(b,to,t[i][j]);
          w.ins(to,b,0);
          w.ins(a,b,s[i][j]+t[i][j]);
          w.ins(b,a,s[i][j]+t[i][j]);
          ans+=s[i][j]+t[i][j];
        }
    }
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<m; ++j)
        {
          scanf("%d",&t[i][j]);
        }
    }
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<m; ++j)
        {
          scanf("%d",&s[i][j]);
        }
    }
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<m; ++j)
        {
          int a=(i-1)*m+j,b=(i-1)*m+j+1,to=n*m+1;
          w.ins(0,a,s[i][j]);
          w.ins(a,0,0);
          w.ins(0,b,s[i][j]);
          w.ins(b,0,0);
          w.ins(b,to,t[i][j]);
          w.ins(to,b,0);
          w.ins(a,to,t[i][j]);
          w.ins(to,a,0);
          w.ins(a,b,s[i][j]+t[i][j]);
          w.ins(b,a,s[i][j]+t[i][j]);
          ans+=s[i][j]+t[i][j];
        }
    }
  printf("%d\n",ans-(w.dinic()>>1));
  return 0;
}