[最小割] 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

 

题解

  • 假设割一条s->i的边表示i选文科(称i为文科节点)
  • 那么假如一个集合内的人都选文会获得一个满意度,建立一个新节点连到s流量为满意度,在新节点和每个理科节点连上一条流量为正无穷的边
  • 只要集合内的任意一点选文科则必须要割掉这条边
  • 理科同理

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define inf 1000000000
 6 using namespace std;
 7 int ans,tot,n,m,T,cnt=1,Q[30005],head[30005],state[30005];
 8 int dx[5]={0,0,1,-1,0},dy[5]={1,-1,0,0,0};
 9 struct edge{ int to,from,v; }e[1000005];
10 void insert(int x,int y,int v)
11 {
12     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v;
13     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=0;
14 }
15 bool bfs()
16 {
17     int p=0,q=1;
18     memset(state,-1,sizeof(state));
19     state[0]=Q[0]=0;
20     while (p!=q)
21     {
22         int u=Q[p]; p++;
23         for (int i=head[u];i;i=e[i].from) if (e[i].v&&state[e[i].to]==-1) state[e[i].to]=state[u]+1,Q[q++]=e[i].to;
24     }
25     return state[T]!=-1;
26 }
27 int dfs(int x,int maxf)
28 {
29     if (x==T) return maxf;
30     int f=0,r;
31     for (int i=head[x];i;i=e[i].from)
32         if (e[i].v&&state[e[i].to]==state[x]+1)
33         {
34             r=dfs(e[i].to,min(e[i].v,maxf-f)),e[i].v-=r,e[i^1].v+=r,f+=r;
35             if (f==maxf) return f;
36         }
37     if (!f) state[x]=-1;
38     return f;
39 }
40 int main()
41 {
42     scanf("%d%d",&n,&m),T=3*n*m+1;
43     for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),insert(0,(i-1)*m+j,x),tot+=x;
44     for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),insert((i-1)*m+j,T,x),tot+=x;
45     for (int i=1,v;i<=n;i++)
46         for (int j=1;j<=m;j++)
47         {
48             scanf("%d",&v),tot+=v;
49             for (int k=0;k<5;k++)
50             {
51                 int x=dx[k]+i,y=dy[k]+j;
52                 if (x>n||y>m||x<1||y<1) continue;
53                 insert((i-1)*m+j+n*m,(x-1)*m+y,inf);
54             }
55             insert(0,(i-1)*m+j+n*m,v);
56         }
57     for (int i=1,v;i<=n;i++)
58         for (int j=1;j<=m;j++)
59         {
60             scanf("%d",&v),tot+=v;
61             for (int k=0;k<5;k++)
62             {
63                 int x=dx[k]+i,y=dy[k]+j;
64                 if (x>n||y>m||x<1||y<1) continue;
65                 insert((x-1)*m+y,(i-1)*m+j+2*n*m,inf);
66             }
67             insert((i-1)*m+j+2*n*m,T,v);
68         }
69     while (bfs()) ans+=dfs(0,inf);
70     printf("%d",tot-ans);
71 }

 

posted @ 2019-07-09 14:34  BEYang_Z  阅读(178)  评论(0编辑  收藏  举报