3894: 文理分科
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 674 Solved: 392
[Submit][Status][Discuss]
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
一个人要不选文,要不选理,必须放弃一个
如果没有相邻的神秘加成,直接:
s--文的满意值-->人--理的满意值-->t
那么现在有神秘加成,如何把这个东西割去
对于文科的神秘加成,建一个点连s容量为全部选文的满意值,这个点连四周的人容量INF,这样的话这个满意值和那些人选理的满意值必须有一个被割去
理科同理
注意
连四周也要连自己啊啊啊啊啊啊啊
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=3e4+5,M=2e5+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f; } int n,m,num,s,t,a,b,c; struct edge{ int v,c,f,ne; }e[M<<1]; int cnt,h[N]; inline void ins(int u,int v,int c){//printf("ins %d %d %d\n",u,v,c); cnt++; e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt; } int q[N],head,tail,vis[N],d[N]; bool bfs(){ memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); head=tail=1; d[s]=0;vis[s]=1; q[tail++]=s; while(head!=tail){ int u=q[head++]; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!vis[v]&&e[i].c>e[i].f){ vis[v]=1; d[v]=d[u]+1; q[tail++]=v; if(v==t) return true; } } } return false; } int cur[N]; int dfs(int u,int a){ if(u==t||a==0) return a; int flow=0,f; for(int &i=cur[u];i;i=e[i].ne){ int v=e[i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){ flow+=f; e[i].f+=f; e[((i-1)^1)+1].f-=f; a-=f; if(a==0) break; } } return flow; } int dinic(){ int flow=0; while(bfs()){ for(int i=s;i<=t;i++) cur[i]=h[i]; flow+=dfs(s,INF); } return flow; } inline int id(int i,int j){return (i-1)*m+j;} int ans; int main(){ //freopen("in.txt","r",stdin); n=read();m=read(); num=n*m; s=0;t=num*3+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a=read(),ins(s,id(i,j),a),ans+=a; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b=read(),ins(id(i,j),t,b),ans+=b; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ c=read();int k=id(i,j)+num;ans+=c; ins(s,k,c); ins(k,id(i,j),INF); if(i-1>=1) ins(k,id(i-1,j),INF); if(j+1<=m) ins(k,id(i,j+1),INF); if(i+1<=n) ins(k,id(i+1,j),INF); if(j-1>=1) ins(k,id(i,j-1),INF); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ c=read();int k=id(i,j)+num+num;ans+=c; ins(k,t,c); ins(id(i,j),k,INF); if(i-1>=1) ins(id(i-1,j),k,INF); if(j+1<=m) ins(id(i,j+1),k,INF); if(i+1<=n) ins(id(i+1,j),k,INF); if(j-1>=1) ins(id(i,j-1),k,INF); } printf("%d",ans-dinic()); }