【BZOJ2127】happiness 最小割
题目大意:有一个$n\times m$的矩阵,矩阵的每个位置上有一个同学,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。求一个方案,使得全班的喜悦值总和最大。
数据范围:$n,m≤100$,权值$≤5000$。
此题直接最小割,对于一对相邻的同学$(A,B)$,设$L_A$表示$A$同学选理的喜悦值,$W_A$表示$A$同学选文的喜悦值(前面说的两种情况$B$同理),设$L$为两个人都选理的额外收获喜悦值,$W$为两个人都选文的额外收获喜悦值,则有:
$S->A$ ,权值为:$L_A+\frac{1}{2}L$
$A->T$ ,权值为:$W_A+\frac{1}{2}W$
$S->A$ ,权值为:$L_A+\frac{1}{2}L$
$A->T$ ,权值为:$W_A+\frac{1}{2}W$
$A<->B$,权值为:$\frac{1}{2}(L+W)$
当点数变多的时候,情况会有所不同,基于这个思路简单变形下就好了
建完图后跑最大流就行了
B站上的数据比较水,我们OJ上的数据加强了必须加上一个特殊的剪枝才能过(新姿势get)
1 #include<bits/stdc++.h>
2 #define M 300005
3 #define N 105
4 #define INF 1145141919
5 #define F(_x,_y) for(int i=1;i<=(_x);i++) for(int j=1;j<=(_y);j++)
6 using namespace std;
7
8 struct edge{int u,v,next;}e[M]={0}; int head[M]={0},use=0;
9 void add(int x,int y,int z){e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use++;}
10 void Add(int x,int y,int z){add(x,y,z); add(y,x,0);}
11 int n,m,a[N][N]={0},b[N][N]={0},sum=0,id[N][N]={0},d[N][N]={0},r[N][N]={0},cnt=0;
12 int S,T,vis[M]={0}; queue<int> q;
13
14 bool bfs(){
15 q.push(S); memset(vis,0,(cnt+1)<<2); vis[S]=1;
16 while(!q.empty()){
17 int u=q.front(); q.pop();
18 for(int i=head[u];~i;i=e[i].next)
19 if(e[i].v&&vis[e[i].u]==0){
20 vis[e[i].u]=vis[u]+1;
21 q.push(e[i].u);
22 }
23 }
24 return vis[T];
25 }
26 int dfs(int x,int flow){
27 if(x==T) return flow; int sum=0;
28 for(int i=head[x];~i;i=e[i].next)
29 if(e[i].v&&vis[e[i].u]==vis[x]+1){
30 int k=dfs(e[i].u,min(flow,e[i].v));
31 e[i].v-=k; e[i^1].v+=k;
32 sum+=k; flow-=k;
33 if(flow==0) return sum;
34 }
35 if(sum==0) vis[x]=-1;
36 return sum;
37 }
38 int dinic(){
39 int res=0;
40 while(bfs())
41 res+=dfs(S,INF);
42 return res;
43 }
44
45 int main(){
46 //freopen("in.txt","r",stdin);
47 memset(head,-1,sizeof(head));
48 S=0; T=1; cnt=1;
49 scanf("%d%d",&n,&m);
50 F(n,m) id[i][j]=++cnt;
51 F(n,m) scanf("%d",&a[i][j]),sum+=a[i][j],a[i][j]<<=1;
52 F(n,m) scanf("%d",&b[i][j]),sum+=b[i][j],b[i][j]<<=1;
53 F(n-1,m){
54 int x; scanf("%d",&x);
55 a[i][j]+=x; a[i+1][j]+=x; sum+=x; d[i][j]+=x;
56 }
57 F(n-1,m){
58 int x; scanf("%d",&x);
59 b[i][j]+=x; b[i+1][j]+=x; sum+=x; d[i][j]+=x;
60 }
61 F(n,m-1){
62 int x; scanf("%d",&x);
63 a[i][j]+=x; a[i][j+1]+=x; sum+=x; r[i][j]+=x;
64 }
65 F(n,m-1){
66 int x; scanf("%d",&x);
67 b[i][j]+=x; b[i][j+1]+=x; sum+=x; r[i][j]+=x;
68 }
69 F(n,m){
70 Add(S,id[i][j],a[i][j]);
71 Add(id[i][j],T,b[i][j]);
72 }
73 F(n,m-1){
74 add(id[i][j],id[i][j+1],r[i][j]);
75 add(id[i][j+1],id[i][j],r[i][j]);
76 }
77 F(n-1,m){
78 add(id[i][j],id[i+1][j],d[i][j]);
79 add(id[i+1][j],id[i][j],d[i][j]);
80 }
81 int hh=dinic();
82 hh>>=1;
83 cout<<sum-hh<<endl;
84 }