【BZOJ2127】happiness 最小割

题目大意:有一个n×m的矩阵,矩阵的每个位置上有一个同学,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。求一个方案,使得全班的喜悦值总和最大。

数据范围:n,m100,权值5000
此题直接最小割,对于一对相邻的同学(A,B),设LA表示A同学选理的喜悦值,WA表示A同学选文的喜悦值(前面说的两种情况B同理),设L为两个人都选理的额外收获喜悦值,W为两个人都选文的额外收获喜悦值,则有:
S>A ,权值为:LA+12L
A>T ,权值为:WA+12W
S>A ,权值为:LA+12L
A>T ,权值为:WA+12W
A<>B,权值为:12(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 }
复制代码

 

posted @   AlphaInf  阅读(125)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示