题目链接:BZOJ - 3894

题目分析

最小割模型,设定一个点与 S 相连表示选文,与 T 相连表示选理。

那么首先要加上所有可能获得的权值,然后减去最小割,即不能获得的权值。

那么对于每个点,从 S 向它连权值为它选文的价值的边,从它向 T 连权值为它选理的价值的边。

对于一个点,它和与它相邻的点构成了一个集合,这个集合如果都选文,可以获得一个价值v1,如果都选理,可以获得一个价值 v2。

只要这个集合中有一个点选文,就无法获得 v2,只要有一个点选理,就无法获得 v1。

那么处理方式就是,新开一个点,从它向 T 连 v2 的边,从这个集合中的每个点向它连 INF 边。这样,只要集合中有一个点选文,就必须割掉 v2。

v1的处理同理。

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; const int MaxN = 100 + 5, MaxNode = 30000 + 15, Dx[5] = {0, 0, 1, -1}, Dy[5] = {1, -1, 0, 0}, INF = 999999999; int n, m, S, T, Tot, Sum, MaxFlow;
int Idx[MaxN][MaxN], Wk[MaxN][MaxN][3], Lk[MaxN][MaxN][3], Num[MaxNode], d[MaxNode]; struct Edge
{
int v, w;
Edge *Next, *Other;
} E[MaxNode * 16], *P = E, *Point[MaxNode], *Last[MaxNode]; inline void AddEdge(int x, int y, int z)
{
Edge *Q = ++P; ++P;
P -> v = y; P -> w = z;
P -> Next = Point[x]; Point[x] = P; P -> Other = Q;
Q -> v = x; Q -> w = 0;
Q -> Next = Point[y]; Point[y] = Q; Q -> Other = P;
} inline int gmin(int a, int b) {return a < b ? a : b;} int DFS(int Now, int Flow)
{
if (Now == T) return Flow;
int ret = 0;
for (Edge *j = Last[Now]; j; j = j -> Next)
if (j -> w && d[Now] == d[j -> v] + 1)
{
Last[Now] = j;
int p = DFS(j -> v, gmin(j -> w, Flow - ret));
ret += p; j -> w -= p; j -> Other -> w += p;
if (ret == Flow) return ret;
}
if (d[S] >= Tot) return ret;
if (--Num[d[Now]] == 0) d[S] = Tot;
++Num[++d[Now]];
Last[Now] = Point[Now];
return ret;
} inline bool Inside(int x, int y)
{
if (x < 1 || x > n) return false;
if (y < 1 || y > m) return false;
return true;
} int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
Idx[i][j] = (i - 1) * m + j;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Wk[i][j][0]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Lk[i][j][0]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Wk[i][j][1]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Lk[i][j][1]);
Tot = n * m * 3; S = ++Tot; T = ++Tot;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
Sum += Wk[i][j][0] + Wk[i][j][1];
Sum += Lk[i][j][0] + Lk[i][j][1];
AddEdge(S, Idx[i][j], Wk[i][j][0]);
AddEdge(Idx[i][j], T, Lk[i][j][0]);
int x, y;
for (int k = 0; k < 4; ++k)
{
x = i + Dx[k]; y = j + Dy[k];
if (!Inside(x, y)) continue;
AddEdge(Idx[x][y], n * m + Idx[i][j], INF);
AddEdge(n * m * 2 + Idx[i][j], Idx[x][y], INF);
}
AddEdge(Idx[i][j], n * m + Idx[i][j], INF);
AddEdge(n * m * 2 + Idx[i][j], Idx[i][j], INF);
AddEdge(n * m + Idx[i][j], T, Lk[i][j][1]);
AddEdge(S, n * m * 2 + Idx[i][j], Wk[i][j][1]);
}
MaxFlow = 0;
memset(d, 0, sizeof(d));
memset(Num, 0, sizeof(Num)); Num[0] = Tot;
for (int i = 1; i <= Tot; ++i) Last[i] = Point[i];
while (d[S] < Tot) MaxFlow += DFS(S, INF);
printf("%d\n", Sum - MaxFlow);
return 0;
}

  

[BZOJ 3894] 文理分科 【最小割】的更多相关文章

  1. BZOJ 3894: 文理分科 [最小割]

    3894: 文理分科 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 674  Solved: 392[Submit][Status][Discuss] ...

  2. BZOJ 3894 Luogu P4313 文理分科 (最小割)

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

  3. bzoj 3894: 文理分科

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

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

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

  5. P4313 文理分科 最小割

    $ \color{#0066ff}{ 题目描述 }$ 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行描述,每个格 ...

  6. ●BZOJ 3894 文理分科

    题链: https://vijos.org/d/ljt12138/p/58c696b8d3d8a16c62a248d4 (要权限号啊...用这个交吧) 题解: 题目大意:    N*M的矩阵,每个位置 ...

  7. 【BZOJ3894】【Luogu3358】文理分科 - 最小割多选一模型

    链接Click Here 这个题就是个板子的最小割多选一模型啦\(QwQ\),这里介绍一种通用的解法. 抛开组合收益不谈,这个题就是一个简单的最小割模型.我们只需要建出来这样一张图,在上面跑最小割,割 ...

  8. 【BZOJ3894】文理分科 最小割

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

  9. bzoj 3894 文理分科【最小割+dinic】

    谁说这道和2127是双倍经验的来着完全不一样啊? 数组开小会TLE!数组开小会TLE!数组开小会TLE! 首先sum统计所有收益 对于当前点\( (i,j) \)考虑,设\( x=(i-1)*m+j ...

随机推荐

  1. 备战“软考”之软件project

    说到"软件project"就有一种非常纠结的感觉!为什么呢?由于刚进入软考复习阶段,大家都把它放到了"比較"次要的地位,由于已经学过两遍,再加上它没有非常难理解 ...

  2. activity-intent-startActivity-startActivityResult

    一. Intent和startActivity 1.在一个Activtiy中可以使用startActivity()去开始另一个制定的Activity 但在android3.0(是针对平板出的产品)之后 ...

  3. 一句代码,更加优雅的调用KVO和通知

    来源:wazrx 链接:http://www.jianshu.com/p/70b2503d5fd1 写在前面 每次使用KVO和通知我就觉得是一件麻烦的事情,即便谈不上麻烦,也可说是不方便吧,对于KVO ...

  4. hdu2034java

    人见人爱A-B Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. Android 自定义View修炼-自定义可动画展开收缩View的实现

    有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...

  6. linux下安装redis并自启动

    最近需要使用redis作为tomcat集群的session存储介质,因此记录redis的安装步骤.redis是一款高性能的nosql,支持异步将缓存写入到磁盘中,避免宕机的意外情况导致的缓存信息丢失. ...

  7. PHP金字塔的输出

    相信学习语言的最初的时候,学到循环的时候,开始一定有种摸不着头脑,想砸电脑的冲动吧 这里就是记录我当初学习的时候,为了通过这个循环,学习的金字塔的输出 1.首先,要了解一个金字塔的输出就要去看它的表达 ...

  8. 一个实例明白AutoResetEvent和 ManulResetEvent的用法

    先看一段代码: public class WaitHandlerExample {                 public static AutoResetEvent waitHandler;  ...

  9. who am i

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  10. DOM中的范围 createRange()

    学习<JavaScript 高级程序设计> 12章dom范围的笔记 dom2级在Document类型中定义了 createRange()方法: 创建range对象很简单 var range ...