题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3894

(luogu) https://www.luogu.org/problemnew/show/P4313

题解:

做法很简单,就是最小割,\(S\)集属于文科,\(T\)集属于理科,对于每个点\(i\), 起点\(S\)向\(i\)连\(a_i\)(文科收益/理科代价),\(i\)向终点\(T\)连\(b_i\) (理科收益/文科代价),对于每一个点\(i\)再新建两点\(i_a\)(同文点)和\(i_b\)(同理点),\(S\)向\(i_a\)连边\(aa_i\)(同文收益),\(i_b\)向\(T\)连\(bb_i\)(同理收益),中间对于\(i\)和\(i\)座位相连的每个点,从\(i_a\)向该点连边,从该点向\(i_b\)连边,边权均为\(+\inf\).

我的错误做法: 如果同文同理建成同一个点,和座位相连的每个点连双向边,那么这是错的,如果连单向边也是错的。因为建两个点实际上可以保证如果\(i_a\)属于\(S\)集则它连向的人都选文,如果\(i_b\)属于\(T\)集则连向它的人都选理,如果它们与\(S,T\)之间的边都被割掉了,则它们对这些人没有任何限制,这些人仍是独立的。但如果同文同理建成同一个点连双向边,那么这些点之间构成强连通分量,相当于默认所有人必须在同一集合,这是最离谱的做法我居然能想出来。如果连单向边呢,比如从新点往这几个人连边,从\(S\)往新点连边,从新点往\(T\)连边,那么相当于规定“如果新点属于\(S\)则这些人全属于\(S\), 如果新点属于\(T\)则对这些人没有要求”。总之,从\(i\)往\(j\)连边\(\inf\)则相当于如果\(i\in S\)则\(j\in S\), 但是如果\(i\in T\)则对\(j\)没有要求;如果\(j\in T\)则\(i\in T\),而如果\(j\in S\)则没有要求对\(i\)没有要求(这两句话是等价的)。\(i\)和\(j\)之间连双向\(\inf\)边则相当于强制两点在同一集合中。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cassert>
using namespace std;const int INF = 1e8;namespace MaxFlow
{const int N = 3e4+2;const int M = 14e4;struct Edge{int v,w,nxt,rev;} e[(M<<1)+3];int fe[N+3];int te[N+3];int que[N+3];int dep[N+3];int n,en,s,t;void addedge(int u,int v,int w){en++; e[en].v = v; e[en].w = w;e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;en++; e[en].v = u; e[en].w = 0;e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;}bool bfs(){for(int i=1; i<=n; i++) dep[i] = 0;int head = 1,tail = 1; que[tail] = s; dep[s] = 1;while(head<=tail){int u = que[head]; head++;for(int i=fe[u]; i; i=e[i].nxt){if(dep[e[i].v]==0 && e[i].w>0){dep[e[i].v] = dep[u]+1;tail++; que[tail] = e[i].v;}}}return dep[t]!=0; }int dfs(int u,int cur){if(u==t) {return cur;}int rst = cur;for(int i=te[u]; i; i=e[i].nxt){if(dep[e[i].v]==dep[u]+1 && e[i].w>0 && rst>0){int flow = dfs(e[i].v,min(rst,e[i].w));if(flow>0){rst -= flow; e[i].w -= flow; e[e[i].rev].w += flow;if(e[i].w>0) {te[u] = i;}if(rst==0) return cur;}}}if(cur==rst) dep[u] = 0;return cur-rst;}int dinic(int _n,int _s,int _t){int ret = 0;n = _n,s = _s,t = _t;while(bfs()){for(int i=1; i<=n; i++) te[i] = fe[i];ret += dfs(s,INF);}return ret;}
}
using MaxFlow::addedge;
using MaxFlow::dinic;const int N = 100;
int a[N+3][N+3],b[N+3][N+3],aa[N+3][N+3],bb[N+3][N+3];
int n,m;int getid(int x,int y) {return (x-1)*m+y+2;}int main()
{scanf("%d%d",&n,&m); int ans = 0;for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){scanf("%d",&a[i][j]); ans += a[i][j];}}for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){scanf("%d",&b[i][j]); ans += b[i][j];}}for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){scanf("%d",&aa[i][j]); ans += aa[i][j];}}for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){scanf("%d",&bb[i][j]); ans += bb[i][j];}}for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){int x = getid(i,j);addedge(1,x,a[i][j]);addedge(x,2,b[i][j]);addedge(1,x+n*m,aa[i][j]);addedge(x+n*m*2,2,bb[i][j]);addedge(x+n*m,x,INF);addedge(x,x+n*m*2,INF);if(i>1){addedge(x+n*m,getid(i-1,j),INF);addedge(getid(i-1,j),x+n*m*2,INF);}if(j>1){addedge(x+n*m,getid(i,j-1),INF);addedge(getid(i,j-1),x+n*m*2,INF);}if(i<n){addedge(x+n*m,getid(i+1,j),INF);addedge(getid(i+1,j),x+n*m*2,INF);}if(j<m){addedge(x+n*m,getid(i,j+1),INF);addedge(getid(i,j+1),x+n*m*2,INF);}}}int tmp = dinic(n*m*3+2,1,2);ans -= tmp;printf("%d\n",ans);return 0;
}

BZOJ 3894 Luogu P4313 文理分科 (最小割)相关推荐

  1. bzoj 3894: 文理分科 最小割

    Description 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行 描述,每个格子代表一个同学的座位.每位 ...

  2. BZOJ 3894 文理分科 最小割

    题目大意:给定一个m*n的矩阵,每个格子的人可以学文或者学理,学文和学理各有一个满意度,如果以某人为中心的十字内所有人都学文或者学理还会得到一个额外满意度,求最大满意度之和 令S集为学文,T集为学理 ...

  3. 文理分科 (最小割问题)

    Description 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行描述,每个格子代表一个同学的座位.每位同学 ...

  4. LuoguP4313 BZOJ3894 文理分科——最小割

    洛谷:文理分科 传送门 题目描述: 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行描述,每个格子代表一个同学的座位.每位同学必须从文科和理科中选择一科.同学们在选择科目的时候会获得一 ...

  5. bzoj3894 文理分科 最小割

    Description 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行 描述,每个格子代表一个同学的座位.每位 ...

  6. 【BZOJ3894】文理分科 最小割 (再不刷它就土了,毕竟水题)

    #include <stdio.h> int main() {puts("转载请注明出处[vmurder]谢谢");puts("网址:blog.csdn.ne ...

  7. (最小割)洛谷P4313文理分科

    洛谷P4313文理分科 思路: 一下子就可以想到最小割,先不考虑一起选的情况的话,就是文理二者择其一的选择. SSS向(i,j)(i,j)(i,j)建边,权值为arti,jart_{i,j}arti, ...

  8. P4313 文理分科 详细理解

    P4313 文理分科 网络其他地方看到的原话:在说这道题之前,让我们先思考一下最小割的性质.最小割就是使得s到t割掉的最小边的容量,割过之后,所有的点要么与s联通,要么与t联通. 这样的性质,即要么与 ...

  9. P4313 文理分科

    HyperlinkHyperlinkHyperlink https://www.luogu.com.cn/problem/P4313 DescriptionDescriptionDescription ...

最新文章

  1. 第八章 让开发板发出声音:蜂鸣器驱动读后感
  2. 使用WebStor快速检查你组织网络中的所有网站相关安全技术
  3. h2 不能访问localhost_个人学习系列 - Spring Boot 整合 H2
  4. 1.1 决策树算法原理
  5. ajax传递json对象 php,ajax 和 php 相互传递 JSON对象(转载)
  6. express+handlebars 快速搭建网站前后台
  7. 为什么阿里巴巴不允许使用Executors?
  8. oracle foreign 查询,ORACLE foreign key
  9. SQL语句(二)创建带主键和约束的数据表
  10. 学习笔记-关于pf标志位
  11. FPGA——用VGA时序显示图像原理详解(2)
  12. org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.Mav
  13. 记一次组装电脑的经历
  14. VAS价值存托公链体系创世录 第一章
  15. 摄像头参数介绍 ———— 信噪比(SNR)
  16. Appium在Android无法显示界面处理方式
  17. pixijs微信小游戏排行榜开放域开发
  18. 费纸箱手工制作机器人_废纸板制作机器人玩具,好玩还省钱!做亲子手工必学...
  19. 整理android逆向工程师技能表 by非虫from看雪
  20. Rainbow Brackets插件的一个好看的颜色搭配

热门文章

  1. VS2010中使用正则表达式替换时无法使用回车符的解决方法
  2. VirtualBox使用技巧
  3. C++ Builder 导入 lib 库语法
  4. BugkuCTF-Misc:猜
  5. Java中this的简单应用
  6. windows调试器设置
  7. 数据结构与算法---笔记
  8. 从JDK9的Flow接口说起
  9. C语言再学习-- assert 断言宏
  10. 【译】Beyond Snarks: Some Blockchain Privacy Protocols You Need to Know About