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
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; }