题目链接:BZOJ - 2127

题目分析

首先,每个人要么学文科,要么学理科,所以可以想到是一个最小割模型。

我们就确定一个人如果和 S 相连就是学文,如果和 T 相连就是学理。

那么我们再来确定建图。首先使用最小割,就是先加上所有可能获得的权值,再减去最小割(即不能获得的权值)。

如果一个人学理,就要割掉与 S 相连的边,那么就是要割掉学文的收益。于是,对于每个点,从 S 向它连边,权值为它学文的收益。

同理,对于每个点,从它向 T 连边,权值为它学理的收益。

对于两个相邻的人,他们有同时学文的收益和同时学理的收益。

如果他们都学文,就会失去同时学理的收益,于是从他们分别向 T 连边,权值为他们同时学理收益的一半。

同理,从 S 向他们分别连边,权值为他们同时学文收益的一半。

但是如果一个人学文一个人学理,就要失去同时学文和同时学理的收益,因此,在他们之前连双向边,权值为同时学文的收益加同时学理的收益的一半。

这样建图,就巧妙地实现了控制不同的收益。

由于建图的时候权值的一半可能不是整数,先将权值乘 2 ,最后再除以 2 。

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm> using namespace std; const int MaxN = 100 + 5, MaxNode = 10000 + 15, INF = 999999999; int n, m, Sum, S, T, Tot, MaxFlow;
int Idx[MaxN][MaxN], Wk[MaxN][MaxN][5], Lk[MaxN][MaxN][5], Num[MaxNode], d[MaxNode]; struct Edge
{
int v, w;
Edge *Next, *Other;
} E[MaxNode * 12], *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;
} 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;
S = n * m + 1; T = n * m + 2; Tot = T;
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 - 1; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Wk[i][j][1]);
for (int i = 1; i <= n - 1; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &Lk[i][j][1]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m - 1; ++j)
scanf("%d", &Wk[i][j][2]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m - 1; ++j)
scanf("%d", &Lk[i][j][2]);
int v1, v2, v3;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
Sum += Wk[i][j][0] + Wk[i][j][1] + Wk[i][j][2];
Sum += Lk[i][j][0] + Lk[i][j][1] + Lk[i][j][2];
v1 = Wk[i][j][0] * 2 + Wk[i][j][1] + Wk[i][j][2];
v2 = Lk[i][j][0] * 2 + Lk[i][j][1] + Lk[i][j][2];
v1 += Wk[i - 1][j][1]; v2 += Lk[i - 1][j][1];
v1 += Wk[i][j - 1][2]; v2 += Lk[i][j - 1][2];
AddEdge(S, Idx[i][j], v1);
AddEdge(Idx[i][j], T, v2);
if (i < n)
{
v3 = Wk[i][j][1] + Lk[i][j][1];
AddEdge(Idx[i][j], Idx[i + 1][j], v3);
AddEdge(Idx[i + 1][j], Idx[i][j], v3);
}
if (j < m)
{
v3 = Wk[i][j][2] + Lk[i][j][2];
AddEdge(Idx[i][j], Idx[i][j + 1], v3);
AddEdge(Idx[i][j + 1], Idx[i][j], v3);
}
}
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);
Sum -= MaxFlow >> 1;
printf("%d\n", Sum);
return 0;
}

  

[BZOJ 2127] happiness 【最小割】的更多相关文章

  1. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  2. [置顶] [BZOJ]2127: happiness 最小割

    happiness: Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己 ...

  3. BZOJ 2127: happiness(最小割解决集合划分)

    Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 2350  Solved: 1138[Submit][Status][Discuss] Descript ...

  4. BZOJ 2127 / Luogu P1646 [国家集训队]happiness (最小割)

    题面 BZOJ传送门 Luogu传送门 分析 这道题又出现了二元关系,于是我们只需要解方程确定怎么连边就行了 假设跟SSS分在一块是选文科,跟TTT分在一块是选理科,先加上所有的收益,再来考虑如何让需 ...

  5. [国家集训队]happiness 最小割 BZOJ 2127

    题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文 ...

  6. bzoj 2127 happiness【最小割+dinic】

    参考:https://www.cnblogs.com/chenyushuo/p/5144957.html 不得不说这个建图方法真是非常妙啊 假设S点选理,T点选文,a[i][j]为(i,j)选文收益, ...

  7. [bzoj2127]happiness——最小割

    这个题太恶心了...并不想继续做了... 本代码在bzoj上TLE! 大致说一下思路: 建立ST,首先由S连边(S,u,a)a代表学文的分数,连向T(u,T,b)b表示学理的分数,这样构造出了两个人独 ...

  8. spoj 839 OPTM - Optimal Marks&&bzoj 2400【最小割】

    因为是异或运算,所以考虑对每一位操作.对于所有已知mark的点,mark的当前位为1则连接(s,i,inf),否则连(i,t,inf),然后其他的边按照原图连(u,v,1),(v,u,1),跑最大流求 ...

  9. bzoj 2127: happiness

    #include<cstdio> #include<iostream> #include<cstring> #define M 100009 #define inf ...

随机推荐

  1. 日志分析(php+nosql+rsync+crontable)

    是不是经常要分析用户的行为?是不是经常遇到多台server上传的日志一起分析?是不是对数据统计的间隔时间要求非常短?还有木有由于日志文件过大,而须要分块处理? 1.说明一点在日志写入的时候必须依照一种 ...

  2. Windows 7系统下局域网文件共享设置方法

    今天给家里增添了一台组装机,小试了一下win7局域网文件共享功能,很爽的说. 记录一下实现方法: 1.关闭防火墙 2.启用共享. 控制面板 – 网络和共享中心 – 更改高级共享设置,将图中的几个选项选 ...

  3. 分分钟解决iOS开发中App启动广告的功能

    前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏 ...

  4. Google Map API v2 番外篇 关于gps位置偏差及修正方法探讨

    我的手机是M35C,在我自己的map activity中,通过gps获取到的经纬度比实际地址总是有500米左右的偏差. 在网上搜索了很多,都说这个是测绘局为了保密故意弄成这样的.gps全球定位系统获得 ...

  5. SQL给字段加上统一的某个字符

    表名:News  字段名:No_id Update News set No_id='字符'+No_id

  6. 微信上传图文消息invalid media_id hint,thumb_media_id怎么获取

    微信上传图文消息thumb_media_id, thumb_media_id怎么获取, 微信群发图文消息invalid media_id hint, 微信群发图文消息40007, 40007,inva ...

  7. css3 文本超出后出现省略号

    clip:当内联内容溢出块容器时,将溢出部分裁切掉. ellipsis:当内联内容溢出块容器时,将溢出部分替换为(...). 当块容器 <' overflow '> 为非visible时, ...

  8. ASP.NET MVC 自我总结的便捷开发实例

    前言 工作了这么久了,接触ASP.NET MVC已经很久了,一直都想总结一下它的一些实用的,经常使用的一些技巧,但是因为一直都很懒,也不想总结,所以一直都没有好好写出来,趁着现在有这种冲劲,那么就先把 ...

  9. swift 关于闭包和函数

    调用函数,有闭包参数时: 函数的实现中:闭包为参数时,有参数返回值类型: 调用闭包时,传入参数 调用函数时:闭包为参数,是闭包的实现,当闭包为最后一个参数时,可写在参数括号外面 即===>函数在 ...

  10. 说说http请求

    为什么做web前端要了解http标准?因为浏览器要从服务端获取网页,网页也可能将信息再提交给服务器,这其中都有http的连接.web系统既然和http链接有瓜葛,你就必须去了解它.我将从一下几个方面讲 ...