题目描述

小B有n个下属,现小B要带着一些下属让别人拍照。

有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影。如果这一些人没带齐那么就不能拍照,小B也不会得到钱。

注意:带下属不是白带的!!!对于每个下属,如果他带了那么小B需要给他一些钱,保证当他拍照时配合。

请问,小B的净收益最多是多少。

输入输出格式

输入格式:

第1行有2个正整数m和n(0<m,n<=100)。接下来的m行,每行是一个要求拍照的人的有关数据。第一个数是他同意支付该合影的费用;接着是该合影需要的若干下属的编号,以一个0作为行的结束标记。最后一行的n个数是带每个下属的费用。

输出格式:

一个数,表示最大收益。小B可以一个人也不带。

题解

  我们把题目用图的形式表示出来:我们把所有的要求看作是点,每个要求的收益看作是这个点的点权,同理每个人也看作是点,每个人的花费的相反数看作是这个点的点权,然后在每个要求与人之间连接有向边。

  就可发现,我们所求的其实就是这个图的最大权闭合子图。

  首先,我们先来解释一下什么叫做闭合图,所谓最大权闭合图指的是对于一个点集,从这个点集中的点出发的所有出边所指向的点也在这个点集中,则这个点集所组成的图就是一个闭合图。举个例子来说:如下图所示,点集{1,2,3,4,5}和点集{1,2,3,4,5,6}所组成的图都是闭合图,而点集{1,2,3,5,6}就不是一个闭合图(6有一条出边指向了4,但是4没在点集中)。而所谓的最大权,就是指的这样的图中点权和最大的。

  求解最大权的闭合子图我们通常是利用网络流进行求解,我们构造一个超级源点(s),把所有的点权为正的点都与之连边,边的容量为这些点的点权;再构造一个超级汇点(t),把所有的点权为负的点都与之连边,边的容量为点权的相反数,另外,这些点之间原有的边保持不变,边的容量为正无穷。即如下图(黑色为点的编号,红色为权值):

  我们来研究以下两个图之间有什么关系:

  • 在第二个图中,关于s-t的最小割是简单割(割边都与S或T相连),显然他不会去割无穷大的边(黑色的边)。
  • 第二个图的关于s-t的每一个简单割产生的两个子图,我们把含有S的称作S图,含有T的称作T图。则S图是闭合子图。

证明:
简单割中不包含无穷大的边(黑色的边),即不包含联通两个图的边(连接在T点上的边除外)。

所以S图中的边所指向的点一定在S图中,即为闭合图。

  • 最小割产生的S图和T图,S图为最大权闭合子图。

证明:

  因为割集中所有的边,不是连接在s上,就是连接在t上;

  我们记割集中,所有连接在s上的边的权值和为x1,所有连接在t上的边的权值和为x2,而割集中所有边权值和为X=x1+x2;

  又,记图S中所有点的权值和为W,记其中正权值之和为w1,负权值之和为 - w2,故W = w1 - w2;

  而 W + X = w1 - w2 + x1 + x2,由于x2 = w2

    (因为图S中所有负权值的点,必然连接到t点,而图S必然要与t分割开;故割集中,“连接在t点上的边权值和”就是“图S中所有负权值点的权值之和,取负”)

  因而W + X = w1 + x1;

  而显然的,w1 + x1是整个图中所有正权值之和,记为SUM;

  故W = SUM - X,即 “图S中所有点的权值和” = “整个图中所有正权值之和”  - “割集中所有边权值和”;

  然后,因为SUM为定值,只要我们取最小割,则“图S中所有点的权值和”就是最大的,即此时图S为图S为最大权闭合子图。

  所以最大权闭合子图的点权之和等于收益点权之和减去最小割。

代码

#include<bits/stdc++.h>
using namespace std; int w[], c[];
vector <int> G[];
int n, m, x;
const int inf = 0x7fffffff; class Graph{
private :
int cnt;
int Head[], Next[], W[], To[];
int Deep[], cur[];
public :
int s, t, n;
void init()
{
cnt = -;
memset(Head, -, sizeof(Head));
memset(Next, -, sizeof(Next));
}
void _Add(int u, int v, int c)
{
Next[++ cnt] = Head[u];
Head[u] = cnt;
W[cnt] = c;
To[cnt] = v;
}
void Add_edge(int x, int y, int w)
{
_Add(x, y, w);
_Add(y, x, );
}
int Dfs(int u, int flow)
{
if(u == t) return flow;
for(int & i = cur[u]; i != -; i = Next[i])
{
if(Deep[To[i]] == Deep[u] + && W[i] != )
{
int di = Dfs(To[i], min(flow, W[i]));
if(di > )
{
W[i] -= di;
W[i ^ ] += di;
return di;
}
}
}
return ;
}
int Bfs()
{
queue <int> q;
for(; !q.empty();) q.pop();
memset(Deep, , sizeof(Deep));
Deep[s] = ; q.push(s);
for(; !q.empty();)
{
int u = q.front(), v; q.pop();
for(int i = Head[u]; i != -; i = Next[i])
if(!Deep[v = To[i]] && W[i])
{
Deep[v] = Deep[u] + ;
q.push(v);
}
}
return Deep[t] > ? : ;
}
int Dinic()
{
int ans;
for(;Bfs();)
{
for(int i = ; i <= n; ++ i) cur[i] = Head[i];
int d;
for(;d = Dfs(s, inf);) ans += d;
}
return ans;
}
}; Graph Map;
int Num = ;
int n1[], n2[]; void Make_picture()
{
Map.s = ++ Num;
for(int i = ; i <= n; ++ i)
{
n1[i] = ++ Num;
Map.Add_edge(Map.s, Num, w[i]);
}
for(int i = ; i <= m; ++ i) n2[i] = ++ Num;
Map.n = Map.t = ++ Num;
for(int i = ; i <= m; ++ i) Map.Add_edge(n2[i], Map.t, c[i]);
for(int i = ; i <= n; ++ i)
for(int j = ; j < G[i].size(); ++ j)
Map.Add_edge(n1[i], n2[G[i][j]], inf);
return ;
}
int sum = ;
int main()
{
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++ i)
{
scanf("%d", &w[i]);
sum += w[i];
for(;;)
{
scanf("%d", &x);
if(!x) break;
G[i].push_back(x);
}
}
for(int i = ; i <= m; ++ i) scanf("%d", &c[i]);
Map.init();
Make_picture();
printf("%d\n", sum - Map.Dinic());
return ;
}

参考资料

[1]Dilthey's Blog:最大权闭合子图-[求最大点权的闭合子图]

[2]洛谷【P3410】拍照

【洛谷P3410】拍照题解(最大权闭合子图总结)的更多相关文章

  1. 洛谷 P2762 太空飞行计划问题 P3410 拍照【最大权闭合子图】题解+代码

    洛谷 P2762 太空飞行计划问题 P3410 拍照[最大权闭合子图]题解+代码 最大权闭合子图 定义: 如果对于一个点集合,其中任何一个点都不能到达此集合以外的点,这就叫做闭合子图.每个点都有一个权 ...

  2. 洛谷 P3410 拍照

    洛谷 P3410 拍照 题目描述 小B有n个下属,现小B要带着一些下属让别人拍照. 有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影.如果这一些人没带齐那么就不能拍照,小B也不会得到钱. ...

  3. 洛谷 P3410 拍照(最大流 + 建图)

    这道题问的是一群人要和另一群人合影,每个客人都有必须在场的人全部在场才能在场,每个客人给的有收入,但是邀请也需要支出,问最大收入? 我觉得可以总结为一类问题,就是有先决条件的网络流问题.看到费用和支出 ...

  4. [HOJ2634] How to earn more 最大权闭合子图

    Xiao Ming is an expert in computer science and technology, so he can get a lot of projects every mon ...

  5. HDU 5855 Less Time, More profit 最大权闭合子图

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5855 Less Time, More profit Time Limit: 2000/1000 MS ...

  6. BZOJ1391/LG4177 「CEOI2008」order 最大权闭合子图

    问题描述 BZOJ1391 LG4177 题解 最大权闭合子图,本质是最小割 在任务和机器中间的边之前权值设为INF,代表不可违背这条规则 本题的租借就相当于允许付出一定代价,违背某个规则,只需要把中 ...

  7. 洛谷 - P1361 - 小M的作物 - 最小割 - 最大权闭合子图

    第一次做最小割,不是很理解. https://www.luogu.org/problemnew/show/P1361 要把东西分进两类里,好像可以应用最小割的模板,其中一类A作为源点,另一类B作为汇点 ...

  8. 洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)

    https://www.luogu.org/problemnew/show/P4174 最大权闭合子图的模板 每个通讯站建一个点,点权为-Pi:每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连 ...

  9. 洛谷 - P2805 - 植物大战僵尸 - 最大流 - 最大权闭合子图

    https://www.luogu.org/problemnew/show/P2805 最大权闭合子图的特点是,假如你要选一个结点,则要先选中它的所有子节点.正权连S负权连T,容量为绝对值,原图有向边 ...

随机推荐

  1. Spring Security认证配置(三)

    学习本章之前,可以先了解下上篇Spring Security认证配置(二) 本篇想要达到这样几个目的: 1.登录成功处理 2.登录失败处理 3.调用方自定义登录后处理类型 具体配置代码如下: spri ...

  2. JS DOM操作(一) 对页面的操作

    DOM ——文档对象模型(Document Object Model)是表示和处理一个HTML或XML文档的常用方法. 在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标 ...

  3. SWT table性能改善 -- 使用VirtualTable

    在SWT程序中使用table展示数据时,如果数据过多,执行起来会比较慢,不过,我们可以借助VirtualTable来解决这一问题. Eclipse官网中关于VirtualTable的说明见:http: ...

  4. python-观察者模式

    源码地址:https://github.com/weilanhanf/PythonDesignPatterns 说明: 存在这样的一种情况:公司领导再开例会那天临时有事,他让秘书给所有会上员工群发了一 ...

  5. js-数字、字符串、布尔值的转换方式

    来自JavaScript秘密花园 1.转换为字符串 '' + 10 === '10'; // true 将一个值加上空字符串可以轻松转换为字符串类型. 2.字符串转换为数字 +'010' === 10 ...

  6. js-权威指南学习笔记19

    第十九章 jQuery类库 1.传递HTML文本字符串给$()方法,jQuery会根据传入的文本创建好HTML元素并封装为jQuery对象返回. 2.想要遍历jQuery对象中的所有元素时,可以调用e ...

  7. python 使用else代替状态变量

    翻看公司的代码文档,在代码风格文档中,写着:为了提高代码的可维护性,代码中减少flag这类状态变量的使用.这个问题,平时确实没有想过,面对这种需求时,第一反应就是使用flag标记状态.那么使用什么样的 ...

  8. 使用python做简单的接口性能测试

    思路:利用ruquest发送请求,利用多线程模拟并发 下面直接上代码: #!/user/bin/env python #coding=utf-8 import requests import date ...

  9. Oracle EBS AR 贷项通知单核销取值

    SELECT cm.trx_number ,fnd_flex_ext.get_segs('SQLGL', 'GL#', gcc.chart_of_accounts_id, ad.code_combin ...

  10. Sqlserver数据库中的临时表详解

    临时表在Sqlserver数据库中,是非常重要的,下面就详细介绍SQL数据库中临时表的特点及其使用,仅供参考. 临时表与永久表相似,但临时表存储在tempdb中,当不再使用时会自动删除.临时表有两种类 ...