建图,使源点为文,汇点为理,初始总喜悦度减可获得的最大喜悦度相当于图的最小割。
先从源点向每个人连流量为选文喜悦度的边,且从每个人向汇点连流量为选理喜悦度的边。然后对于没一组相邻的同学都单独建一个点,若是同选文,就从源点向该点连流量为额外喜悦度的边,且从该点向其所代表的两个人连流量为无线的边,选理道理相似。这样保证了只要任意一人不选该科,就不会获得额外喜悦度。然后跑最大流即可。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=50000,M=300000,inf=0x7fffffff;
namespace io{
const int SIZE=(1<<21)+1;
char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int qr;
#define gc() (iT==iS?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iT==iS?EOF:*iS++):*iS++)
inline void flush(){
fwrite(obuf,1,oS-obuf,stdout);
oS=obuf;
}
inline void putc(char x){
*oS++ =x;
if(oS==oT)flush();
}
template <class I>
inline void gi(I &x){
for(c=gc();c<'0'||c>'9';c=gc());
for(x=0;c>='0'&&c<='9';c=gc())x=x*10+(c&15);
}
template <class I>
inline void print(I &x){
if(!x)putc('0');
while(x)qu[++qr]=x%10+'0',x/=10;
while(qr)putc(qu[qr--]);
}
}
using io::gi;
using io::putc;
using io::print;
struct edge{
int y,f,next;
}data[M];
int n,m,s,t,num,num1,tot,h[N],dep[N],cur[N];
queue<int> q;
inline void addedge(int x,int y,int f){
data[++num].y=y,data[num].f=f,data[num].next=h[x],h[x]=num;
data[++num].y=x,data[num].f=0,data[num].next=h[y],h[y]=num;
}
inline int min1(int a,int b){
return a<b?a:b;
}
inline int bfs(){
memset(dep,0,sizeof dep);
for(int i=s;i<=num1;++i)cur[i]=h[i];
while(!q.empty())q.pop();
dep[s]=1,q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=h[u];i!=-1;i=data[i].next){
int v=data[i].y;
if(!dep[v]&&data[i].f>0)dep[v]=dep[u]+1,q.push(v);
}
}
return dep[t];
}
int dfs(int u,int t,int lim){
if(u==t)return lim;
int res=0;
for(int &i=cur[u];i!=-1;i=data[i].next){
int v=data[i].y;
if(dep[v]==dep[u]+1&&data[i].f>0){
int fmax=dfs(v,t,min1(lim-res,data[i].f));
if(fmax){data[i].f-=fmax,data[i^1].f+=fmax,res+=fmax;if(res==lim)return res;}
}
}
return res;
}
inline int dinic(){
int ans=0;
while(bfs())ans+=dfs(s,t,inf);
return ans;
}
int main(){
gi(n),gi(m);s=0,t=1,tot=0;
memset(h,-1,sizeof h),num=-1;
for(int y=1,i=1;i<=n;++i)for(int x,j=1;j<=m;++j)gi(x),++y,tot+=x,addedge(s,y,x);
for(int y=1,i=1;i<=n;++i)for(int x,j=1;j<=m;++j)gi(x),++y,tot+=x,addedge(y,t,x);
num1=n*m+1;
for(int i=1;i<n;++i)
for(int x,j=1;j<=m;++j){
gi(x),++num1,tot+=x,addedge(s,num1,x),
addedge(num1,(i-1)*m+j+1,inf),addedge(num1,i*m+j+1,inf);
}
for(int i=1;i<n;++i)
for(int x,j=1;j<=m;++j){
gi(x),++num1,tot+=x,addedge(num1,t,x),
addedge((i-1)*m+j+1,num1,inf),addedge(i*m+j+1,num1,inf);
}
for(int i=1;i<=n;++i)
for(int x,j=1;j<m;++j){
gi(x),++num1,tot+=x,addedge(s,num1,x),
addedge(num1,(i-1)*m+j+1,inf),addedge(num1,(i-1)*m+j+2,inf);
}
for(int i=1;i<=n;++i)
for(int x,j=1;j<m;++j){
gi(x),++num1,tot+=x,addedge(num1,t,x),
addedge((i-1)*m+j+1,num1,inf),addedge((i-1)*m+j+2,num1,inf);
}
printf("%d",tot-dinic());
io::flush();
return 0;
}