【BZOJ3894】文理分科
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
题解:BZ3438的简化版
1.S -> 每个同学(i,j) 容量science[i][j]
2.每个同学(i,j) -> T 容量art[i][j]
3.S -> 新建节点(i,j)' 容量same_science[i][j]
4.节点(i,j)' -> (i,j)和相邻的四个同学 容量∞
5.新建节点(i,j)'' -> T 容量same_art[i][j]
6.(i,j)和相邻的四个同学 -> 节点(i,j)'' 容量∞
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #define P(A,B) ((A-1)*m+B) using namespace std; int n,m,cnt,S,T,ans,tot; int to[1000000],next[1000000],val[1000000],head[50000],d[50000]; int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1}; queue<int> q; int rd() { int ret=0; char gc=getchar(); while(gc<'0'||gc>'9') gc=getchar(); while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret; } void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int bfs() { while(!q.empty()) q.pop(); memset(d,0,sizeof(d)); d[S]=1,q.push(S); int i,u; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) { if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } } return 0; } int dfs(int x,int mf) { if(x==T) return mf; int i,k,temp=mf; for(i=head[x];i!=-1;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } } return mf-temp; } int main() { n=rd(),m=rd(); int i,j,k,a; S=0,T=3*n*m+1; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) a=rd(),tot+=a,add(S,P(i,j),a); for(i=1;i<=n;i++) for(j=1;j<=m;j++) a=rd(),tot+=a,add(P(i,j),T,a); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { a=rd(),tot+=a,add(S,P(i,j)+n*m,a),add(P(i,j)+n*m,P(i,j),1<<30); for(k=0;k<4;k++) if(i+dx[k]>0&&i+dx[k]<=n&&j+dy[k]<=m&&j+dy[k]>0) add(P(i,j)+n*m,P(i+dx[k],j+dy[k]),1<<30); } for(i=1;i<=n;i++) for(j=1;j<=m;j++) { a=rd(),tot+=a,add(P(i,j)+2*n*m,T,a),add(P(i,j),P(i,j)+2*n*m,1<<30); for(k=0;k<4;k++) if(i+dx[k]>0&&i+dx[k]<=n&&j+dy[k]<=m&&j+dy[k]>0) add(P(i+dx[k],j+dy[k]),P(i,j)+2*n*m,1<<30); } while(bfs()) ans+=dfs(S,1<<30); printf("%d",tot-ans); return 0; }