高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。
作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。
第一行两个正整数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列的同学同时选择理科获得的额外喜悦值。
这题很显然的网络流,为Mike的农场的简化版;
对于每个人,往S连一条文科喜悦值,向T连一条立刻喜悦值,
对于两者都选文科的情况,新建一个点,向S连一条值为喜悦值的边,再都向那两点连条无限的边,
对于两者都选理科的情况,跟上面差不多,改成向T连边即可,
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define H(i,j) ((i)*m-m+j)
using namespace std;
const int N=150*100*6,maxlongint=1047483640;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,S,T,ans;
int A[N],B[6*N][3],B0=1;
int hv[N],h[N];
void link(int q,int w,int e1,int e2)
{
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e1;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e2;
}
int aug(int q,int e)
{
if(q==T)return e;
int mi=T+1,E=e;
efo(i,q)if(B[i][2])
{
int w=B[i][1];
if(h[q]==h[w]+1)
{
int t=aug(w,min(e,B[i][2]));
e-=t;
B[i][2]-=t;
B[i^1][2]+=t;
if(!e||h[S]>T+1)return E-e;
}
mi=min(mi,h[w]);
}
if(E==e)
{
if(!(--hv[h[q]]))h[S]=T+2;
hv[h[q]=mi+1]++;
}
return E-e;
}
int main()
{
int q,w;
read(n),read(m);
S=0;T=n*m*5-2*m-2*n+1;ans=0;
fo(i,1,n)fo(j,1,m)read(q),link(S,H(i,j),q,0),ans+=q;
fo(i,1,n)fo(j,1,m)read(q),link(H(i,j),T,q,0),ans+=q;
w=n*m;
fo(i,1,n-1)fo(j,1,m)
read(q),link(S,w+H(i,j),q,0),link(w+H(i,j),H(i,j),maxlongint,0),link(w+H(i,j),H(i+1,j),maxlongint,0),ans+=q;
w+=(n-1)*m;
fo(i,1,n-1)fo(j,1,m)
read(q),link(T,w+H(i,j),0,q),link(w+H(i,j),H(i,j),0,maxlongint),link(w+H(i,j),H(i+1,j),0,maxlongint),ans+=q;
w+=(n-1)*m;
fo(i,1,n)
fo(j,1,m-1)
read(q),link(S,w+H(i,j)-i+1,q,0),link(w+H(i,j)-i+1,H(i,j),maxlongint,0),link(w+H(i,j)-i+1,H(i,j+1),maxlongint,0),ans+=q;
w+=n*(m-1);
fo(i,1,n)fo(j,1,m-1)
read(q),link(T,w+H(i,j)-i+1,0,q),link(w+H(i,j)-i+1,H(i,j),0,maxlongint),link(w+H(i,j)-i+1,H(i,j+1),0,maxlongint),ans+=q;
hv[0]=T+1;
while(h[S]<T+2)ans-=aug(S,maxlongint);
printf("%d\n",ans);
return 0;
}