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