BZOJ-3894 文理分科 最小割
题意:给定一个n×m的矩阵,每个格子的人可以学文或者学理,学文和学理各有一个满意度,如果以某人为中心的十字内所有人都学文或者学理还会得到一个额外满意度,求最大满意度之和
给你一个n×m的图,你可以给每个点染1或者0,对于每个点染1或者0都有一个权值的收益,如果一个点周围有公共边的点都选择了1或者0,也会有一个权值的收益,一个给你4个收益矩阵,求最大的收益
题解:
令S为学文,T为学理
每个人学文就S连向人,学理就人连向T
如果某个集合内的人都学理会获得一个满意度,那么就新加一个点,将集合内的所有人向这个点连流量为inf的边,再从这个点向T连一条流量为满意度的边,表示集合内任意一个人学文都要把这个点与T的边割掉
学文同理
再求最小割就行了
其实,学过二元组建图的话就很容易想到,这个问题不过是把多元关系转换成二元关系就好
我们对每个节点x新建两个点x0,x1分别表示x周围是否都是0和是否都是1,就有了四种二元关系
x是0 且 x周围都是0,那么就有v1的收入
x是1 且 x周围都是1,那么就有v2的收入
x周围都是0,与x相邻的点必须为0,如果为1,则造成inf的代价
x周围都是1,与x相邻的点必须为1,如果为0,则造成inf的代价
然后二元组建图即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 30005 4 #define M 300005 5 #define inf 0x7fffffff/3 6 namespace Dinic 7 { 8 int head[N],head2[N],p=1; 9 struct rec 10 { 11 int go,nex,c; 12 }eg[M*2]; 13 void build(int a,int b,int c) 14 { 15 eg[++p]=(rec){b,head[a],-c}; 16 head[a]=p; 17 eg[++p]=(rec){a,head[b],0}; 18 head[b]=p; 19 } 20 int dis[N],q[N],s[N],S,T,stop,ans; 21 bool bfs() 22 { 23 memset(dis,0,sizeof(dis)); 24 dis[T]=1; 25 q[1]=T; 26 for (int p1=1,p2=1;p1<=p2;p1++) 27 { 28 for (int i=head[q[p1]];i;i=eg[i].nex) 29 if (eg[i^1].c<0 && !dis[eg[i].go]) 30 { 31 dis[eg[i].go]=dis[q[p1]]+1; 32 q[++p2]=eg[i].go; 33 } 34 } 35 if (!dis[S]) return 0; 36 memcpy(head2,head,sizeof(head)); 37 return 1; 38 } 39 bool dinic(int p,int top) 40 { 41 if (p==T) 42 { 43 int x=inf; 44 for (int i=1;i<=top-1;i++) if (-eg[s[i]].c<x) x=-eg[s[i]].c,stop=i; 45 for (int i=1;i<=top-1;i++) eg[s[i]].c+=x,eg[s[i]^1].c-=x; 46 ans+=x; 47 return 1; 48 } 49 for (int &i=head2[p];i;i=eg[i].nex) 50 { 51 if (eg[i].c<0 && dis[eg[i].go]==dis[p]-1) 52 { 53 s[top]=i; 54 if (dinic(eg[i].go,top+1) && top!=stop) return 1; 55 } 56 } 57 return 0; 58 } 59 int ask() 60 { 61 ans=0; 62 while (bfs()) dinic(S,1); 63 return ans; 64 } 65 void init(int _S,int _T) 66 { 67 S=_S; 68 T=_T; 69 } 70 } 71 using namespace Dinic; 72 int n,m,a,x,y,id[102][102],anss; 73 int ss,tt; 74 int dx[5]={0,0,1,-1}; 75 int dy[5]={1,-1,0,0}; 76 int main() 77 { 78 scanf("%d%d",&n,&m); 79 int why=0; 80 ss=0;tt=n*m+3+1; 81 for (int i=1;i<=n;i++) 82 for (int j=1;j<=m;j++) id[i][j]=++why; 83 for (int i=1;i<=n;i++) 84 for (int j=1;j<=m;j++) 85 { 86 scanf("%d",&a); 87 anss+=a; 88 build(ss,id[i][j],a); 89 } 90 for (int i=1;i<=n;i++) 91 for (int j=1;j<=m;j++) 92 { 93 scanf("%d",&a); 94 anss+=a; 95 build(id[i][j],tt,a); 96 } 97 98 for (int i=1;i<=n;i++) 99 for (int j=1;j<=m;j++) 100 { 101 scanf("%d",&a); 102 anss+=a; 103 build(ss,id[i][j]+m*n,a); 104 for (int k=0;k<5;k++) 105 { 106 x=i+dx[k]; 107 y=j+dy[k]; 108 if (x<=0 || y<=0 || x>n || y>m) continue; 109 build(id[i][j]+m*n,id[x][y],inf); 110 } 111 } 112 for (int i=1;i<=n;i++) 113 for (int j=1;j<=m;j++) 114 { 115 scanf("%d",&a); 116 anss+=a; 117 build(id[i][j]+2*m*n,tt,a); 118 for (int k=0;k<5;k++) 119 { 120 x=i+dx[k]; 121 y=j+dy[k]; 122 if (x<=0 || y<=0 || x>n || y>m) continue; 123 build(id[x][y],id[i][j]+2*m*n,inf); 124 } 125 } 126 init(ss,tt); 127 printf("%d\n",anss-ask()); 128 }
Anderyi!