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

HINT

 

样例说明

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

1  0  0  1

0  1  0  0

1  0  0  0

 

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

 

题解:

二元组建图:http://www.cnblogs.com/chenyushuo/p/5146626.html 

这看上去是一个多元关系,但我们可以转化为二元关系

我们对每个节点x0新建两个点x1,x2分别表示x0周围是否都是选文和是否都选理,然后有以下四种二元关系

x0选文且x1为是,那么有v1的收入

x0选理且x2为是,那么有v2的收入

x1为是,与x0相邻的点必须选文,如果选了理,则造成inf的代价

x2为是,与x0相邻的点必须选理,如果选了文,则造成inf的代价

然后二元组建图即可

code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 30005
 7 #define maxm 1200000
 8 #define inf 1061109567
 9 using namespace std;
10 char ch;
11 bool ok;
12 void read(int &x){
13     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
15     if (ok) x=-x;
16 }
17 int n,m,sum,pos[105][105][3],x;
18 struct flow{
19     int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm];
20     int dis[maxn],head,tail,list[maxn];
21     bool bo[maxn];
22     void init(){s=0,t=n*m*3+1,tot=1,memset(now,0,sizeof(now));}
23     void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
24     void add(int a,int b,int c){put(a,b,c),put(b,a,0);}
25     bool bfs(){
26         memset(bo,0,sizeof(bo));
27         head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1;
28         while (head<tail){
29             int u=list[++head];
30             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
31                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
32         }
33         return bo[t];
34     }
35     int dfs(int u,int rest){
36         if (u==t) return rest;
37         int ans=0;
38         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
39             if (val[p]&&dis[v]==dis[u]+1){
40                 int d=dfs(v,min(rest,val[p]));
41                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
42             }
43         if (!ans) dis[u]=-1;
44         return ans;
45     }
46     int dinic(){
47         int ans=0;
48         while (bfs()) ans+=dfs(s,inf);
49         return ans;
50     }
51 }f;
52 const int dx[4]={1,0,-1,0};
53 const int dy[4]={0,1,0,-1};
54 int main(){
55     read(n),read(m),f.init();
56     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
57         pos[i][j][0]=(i-1)*m+j,pos[i][j][1]=pos[i][j][0]+n*m,pos[i][j][2]=pos[i][j][1]+n*m;
58     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) read(x),sum+=x,f.add(pos[i][j][0],f.t,x<<1);
59     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) read(x),sum+=x,f.add(f.s,pos[i][j][0],x<<1);
60     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){
61         read(x),sum+=(x<<1);
62         f.add(pos[i][j][0],pos[i][j][1],x),f.add(pos[i][j][1],pos[i][j][0],x);
63         f.add(f.s,pos[i][j][0],x),f.add(f.s,pos[i][j][1],x);
64         f.add(pos[i][j][0],f.t,x<<1),f.add(pos[i][j][1],f.t,x<<1);
65     }
66     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=0;k<4;k++){
67         int x=i+dx[k],y=j+dy[k];
68         if (x<=0||x>n||y<=0||y>m) continue;
69         f.add(pos[x][y][0],pos[i][j][1],inf);
70     }
71     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){
72         read(x),sum+=(x<<1);
73         f.add(pos[i][j][0],pos[i][j][2],x),f.add(pos[i][j][2],pos[i][j][0],x);
74         f.add(pos[i][j][0],f.t,x),f.add(pos[i][j][2],f.t,x);
75         f.add(f.s,pos[i][j][0],x<<1),f.add(f.s,pos[i][j][2],x<<1);
76     }
77     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=0;k<4;k++){
78         int x=i+dx[k],y=j+dy[k];
79         if (x<=0||x>n||y<=0||y>m) continue;
80         f.add(pos[i][j][2],pos[x][y][0],inf);
81     }
82     printf("%d\n",sum-(f.dinic()>>1));
83     return 0;
84 }

 

posted @ 2016-01-21 10:12  chenyushuo  阅读(639)  评论(0编辑  收藏  举报