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 413 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
152HINT
样例说明
1表示选择文科,0表示选择理科,方案如下:
1 0 0 1
0 1 0 0
1 0 0 0 N,M<=100,读入数据均<=500 感觉题目描述有点问题 不看题解根本不知道怎么建图。 分析:首先如果没有相邻全选情况,建图比较容易。文科与S相连,理科与T相连,求最小割,每条路径必定割掉一条边。 下面考虑相邻全选情况。相邻中有任意一人选文,就没有额外的理科加成。同理相邻任意一人选理,就没有额外的文科加成。根据这个可以这样建图,每个点再拆为P1,P2,如图: 1,2,3,4为某个位置的相邻点。与P1相连,流量为inf,这样如果任意一个选文科(假设a[1]),即与S相连,必定会割掉Same_s这条边。因为选a[1],肯定没有s[1],要保持不连通,最小割肯定割Same_s,不会割inf。同理对于Same_a,也一样。任意一个选理科(假设s[3]),与T相连,肯定没有a[3],要保持不连通,最小割肯定割Same_a,不会割inf。 这样建图满足了额外加成的控制。 直接用总的满意度-最小割即可 第一次知道拆点方法,P(i,j) = (i-1)*m+j,然后P1=P(i,j)+n*m P2=P(i,j)+2*n*m
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define P(i,j) (i-1)*m+j 4 5 const int maxn=100010; 6 const int maxm=400010; 7 const int inf=0x3f3f3f3f; 8 struct Edge{ 9 int to,next,cap,flow,cost; 10 }edge[maxm]; 11 12 int tol; 13 int head[maxn]; 14 int gap[maxn],dep[maxn],cur[maxn]; 15 int dir[][2]={0,0,1,0,-1,0,0,-1,0,1}; 16 void init() { 17 tol=0; 18 memset(head,-1,sizeof(head)); 19 } 20 void addedge(int u,int v,int w,int rw=0) { 21 edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0; 22 edge[tol].next=head[u];head[u]=tol++; 23 edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0; 24 edge[tol].next=head[v];head[v]=tol++; 25 } 26 27 int Q[maxn]; 28 void bfs(int start,int end) { 29 memset(dep,-1,sizeof(dep)); 30 memset(gap,0,sizeof(gap)); 31 gap[0]=1; 32 int front=0,rear=0; 33 dep[end]=0; 34 Q[rear++]=end; 35 while(front!=rear) { 36 int u=Q[front++]; 37 for(int i=head[u];i!=-1;i=edge[i].next) { 38 int v=edge[i].to; 39 if(dep[v]!=-1) continue; 40 Q[rear++]=v; 41 dep[v]=dep[u]+1; 42 gap[dep[v]]++; 43 } 44 } 45 } 46 47 int S[maxn]; 48 int sap(int start,int end,int n) { 49 bfs(start,end); 50 memcpy(cur,head,sizeof(head)); 51 int top=0; 52 int u=start; 53 int ans=0; 54 while(dep[start]<n) { 55 if(u==end) { 56 int minn=inf; 57 int inser; 58 for(int i=0;i<top;i++) { 59 if(minn>edge[S[i]].cap-edge[S[i]].flow) { 60 minn=edge[S[i]].cap-edge[S[i]].flow; 61 inser=i; 62 } 63 } 64 for(int i=0;i<top;i++) { 65 edge[S[i]].flow+=minn; 66 edge[S[i]^1].flow-=minn; 67 } 68 ans+=minn; 69 top=inser; 70 u=edge[S[top]^1].to; 71 continue; 72 } 73 bool flag=false; 74 int v; 75 for(int i=cur[u];i!=-1;i=edge[i].next) { 76 v=edge[i].to; 77 if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) { 78 flag=true; 79 cur[u]=i; 80 break; 81 } 82 } 83 if(flag) { 84 S[top++]=cur[u]; 85 u=v; 86 continue; 87 } 88 int minn=n; 89 for(int i=head[u];i!=-1;i=edge[i].next) { 90 if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<minn) { 91 minn=dep[edge[i].to]; 92 cur[u]=i; 93 } 94 } 95 gap[dep[u]]--; 96 if(!gap[dep[u]]) return ans; 97 dep[u]=minn+1; 98 gap[dep[u]]++; 99 if(u!=start) u=edge[S[--top]^1].to; 100 } 101 return ans; 102 } 103 104 int main() { 105 int n,m,x,sum; 106 while(~scanf("%d%d",&n,&m)) { 107 init(); 108 sum=0; 109 int S=0,T=3*n*m+1; 110 for(int i=1;i<=n;i++) { 111 for(int j=1;j<=m;j++) { 112 scanf("%d",&x); 113 sum+=x; 114 addedge(S,P(i,j),x); 115 } 116 } 117 for(int i=1;i<=n;i++) { 118 for(int j=1;j<=m;j++) { 119 scanf("%d",&x); 120 sum+=x; 121 addedge(P(i,j),T,x); 122 } 123 } 124 for(int i=1;i<=n;i++) { 125 for(int j=1;j<=m;j++) { 126 scanf("%d",&x); 127 sum+=x; 128 for(int k=0;k<5;k++) { 129 int newx=i+dir[k][0]; 130 int newy=j+dir[k][1]; 131 if(newx<1||newx>n||newy<1||newy>m) continue; 132 addedge(P(i,j)+2*n*m,P(newx,newy),inf); 133 } 134 addedge(S,P(i,j)+2*n*m,x); 135 } 136 } 137 for(int i=1;i<=n;i++) { 138 for(int j=1;j<=m;j++) { 139 scanf("%d",&x); 140 sum+=x; 141 for(int k=0;k<5;k++) { 142 int newx=i+dir[k][0]; 143 int newy=j+dir[k][1]; 144 if(newx<1||newx>n||newy<1||newy>m) continue; 145 addedge(P(newx,newy),P(i,j)+n*m,inf); 146 } 147 addedge(P(i,j)+n*m,T,x); 148 } 149 } 150 printf("%d\n",sum-sap(0,T,T+1)); 151 } 152 }
标签:分科,head,int,文理,edge,maxn,BZOJ3894,tol,dep 来源: https://www.cnblogs.com/ACMerszl/p/10803661.html