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

 

【BZOJ2127】happiness 最小割

上一篇:Android预置Apk方法


下一篇:0715-----C++Primer听课笔记-----------函数指针 、单例模式