bzoj 3894: 文理分科

Description

 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠
结过)
 小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行
描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择
一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式
得到:
1.如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如
  果选择理科,将得到science[i][j]的满意值。
2.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且
  仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开
  心,所以会增加same_art[i][j]的满意值。
3.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理
  科,则增加same_science[i]j[]的满意值。
  小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。

Input

第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];

Output

输出为一个整数,表示最大的满意值之和

Sample Input

3 4
13 2 4 13
7 13 8 12
18 17 0 5

8 13 15 4
11 3 8 11
11 18 6 5

1 2 3 4
4 2 3 2
3 1 0 4

3 2 3 2
0 2 2 1
0 2 4 4

Sample Output

152

HINT 

样例说明

1表示选择文科,0表示选择理科,方案如下:

1  0  0  1

0  1  0  0

1  0  0  0
 
N,M<=100,读入数据均<=500

Source

一道很不错的最小割模型混杂题,画了好久才跑对QAQ...

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define RG register
using namespace std;
typedef long long ll;
const int N=1000050;
const int Inf=19260817;
int gi(){
  int x=0,flag=1;
  char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*flag;
}
int head[N],nxt[N],to[N],s[N],cnt=1,n,m;
int a[550][550],b[550][550],c[550][550],d[550][550];
int id[550][550][3],tt,S,T,level[N],q[N*5],F,tot;
int mx[5]={1,-1,0,0},my[5]={0,0,1,-1};
inline void Addedge(RG int x,RG int y,RG int z) {
  to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
}
inline void lnk(RG int x,RG int y,RG int z){
  Addedge(x,y,z),Addedge(y,x,0);
}
inline bool bfs(){
  for(RG int i=S;i<=T;i++) level[i]=0;
  q[0]=S,level[S]=1;int t=0,sum=1;
  while(t<sum){
    int x=q[t++];
    if(x==T) return 1;
    for(RG int i=head[x];i;i=nxt[i]){
      int y=to[i];
      if(s[i]&&level[y]==0){
	level[y]=level[x]+1;
	q[sum++]=y;
      }
    }
  }
  return 0;
}
inline int dfs(RG int x,int maxf){
  if(x==T) return maxf;
  int ret=0;
  for(RG int i=head[x];i;i=nxt[i]){
    int y=to[i],f=s[i];
    if(level[y]==level[x]+1&&f){
      int minn=min(f,maxf-ret);
      f=dfs(y,minn);
      s[i]-=f,s[i^1]+=f,ret+=f;
      if(ret==maxf) break;
    }
  }
  if(!ret) level[x]=0;
  return ret;
}
inline void Dinic(){
  while(bfs()) F+=dfs(S,Inf);
}
int main(){
  n=gi(),m=gi();
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
      a[i][j]=gi(),tot+=a[i][j];
    }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
      b[i][j]=gi();tot+=b[i][j];
    }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
      c[i][j]=gi();tot+=c[i][j];
    }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
      d[i][j]=gi();tot+=d[i][j];
    }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      for(int k=0;k<3;k++){
	id[i][j][k]=++tt;
      }
  S=0,T=tt+1;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
      lnk(S,id[i][j][0],a[i][j]);
      lnk(id[i][j][0],T,b[i][j]);
      lnk(id[i][j][0],id[i][j][1],Inf);
      lnk(id[i][j][2],id[i][j][0],Inf);
      lnk(id[i][j][1],T,d[i][j]);
      lnk(S,id[i][j][2],c[i][j]);
      for(int k=0;k<4;k++){
	int x=i+mx[k],y=j+my[k];
	if(1<=x&&x<=n&&1<=y&&y<=m){
	  lnk(id[x][y][0],id[i][j][1],Inf);
	  lnk(id[i][j][2],id[x][y][0],Inf);
	}
      }
    }
  Dinic();printf("%d\n",tot-F);
  return 0;
}
posted @ 2017-06-11 20:01  qt666  阅读(142)  评论(0编辑  收藏  举报