题目描述

小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[105], c[105];
vector <int> G[105];
int n, m, x;
const int inf = 0x7fffffff;class Graph{private :int cnt;int Head[205], Next[100005], W[100005], To[100005];int Deep[205], cur[205];public :int s, t, n;void init(){cnt = -1;memset(Head, -1, sizeof(Head));memset(Next, -1, 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, 0);}int Dfs(int u, int flow){if(u == t)    return flow;for(int & i = cur[u]; i != -1; i = Next[i]){if(Deep[To[i]] == Deep[u] + 1 && W[i] != 0){int di = Dfs(To[i], min(flow, W[i]));if(di > 0){W[i] -= di;W[i ^ 1] += di;return di;}}}return 0;}int Bfs(){queue <int> q;for(; !q.empty();)    q.pop();memset(Deep, 0, sizeof(Deep));Deep[s] = 1; q.push(s);for(; !q.empty();){int u = q.front(), v; q.pop();for(int i = Head[u]; i != -1; i = Next[i])if(!Deep[v = To[i]] && W[i]){Deep[v] = Deep[u] + 1;q.push(v);}} return Deep[t] > 0 ? 1 : 0;}int Dinic(){int ans;for(;Bfs();){for(int i = 1; i <= n; ++ i)    cur[i] = Head[i];int d;for(;d = Dfs(s, inf);)    ans += d;}return ans;}
};Graph Map;
int Num = 0;
int n1[105], n2[105];void Make_picture(){Map.s = ++ Num;for(int i = 1; i <= n; ++ i){n1[i] = ++ Num;Map.Add_edge(Map.s, Num, w[i]);}for(int i = 1; i <= m; ++ i) n2[i] = ++ Num;Map.n = Map.t = ++ Num;for(int i = 1; i <= m; ++ i) Map.Add_edge(n2[i], Map.t, c[i]);for(int i = 1; i <= n; ++ i)for(int j = 0; j < G[i].size(); ++ j)Map.Add_edge(n1[i], n2[G[i][j]], inf);return ;}
int sum = 0;
int main()
{scanf("%d%d", &n, &m);for(int i = 1; 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 = 1; i <= m; ++ i)    scanf("%d", &c[i]);Map.init();Make_picture();printf("%d\n", sum - Map.Dinic());return 0;
}

参考资料

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

[2]洛谷【P3410】拍照

转载于:https://www.cnblogs.com/2020pengxiyue/p/9463055.html

【洛谷P3410】拍照题解(最大权闭合子图总结)相关推荐

  1. luogu P3410 拍照(最大权闭合图转最小割)

    luogu P3410 拍照 最大权闭合图转最小割 要得到最大收益,我们可以用总可能收益减去最小花费,也就是最小割. #include<cstdio> #include<cstrin ...

  2. 洛谷 p4174 [noi2006] 最大获利 最小割(最大流),最大权闭合子图

    题目 题解 题目 洛谷 p4174 建站花费p[i]元,如果a,b两个站都建起来了获利c元,问最大的获利. 题解 首先需要理解最大流求最大权闭合子图,这个我也不说了,又是转载博客. https://b ...

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

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

  4. 洛谷P1816 忠诚 题解

    洛谷P1816 忠诚 题解 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意.但是由于一些人 ...

  5. 线性存储的最短平均检索时间(洛谷P1253题题解,Java语言描述)

    题目要求 P1253题目链接 分析 很像 ~洛谷P1223题题解~,也是一种类似SJF的贪心法. 排个序,由于两个不大于10000的数,乘起来还是int,就使用int属性吧. 数据量小,所以Scann ...

  6. 队列模拟约瑟夫问题(洛谷P1996题题解,Java语言描述)

    题目要求 P1996题目链接 分析 以前就研究过"约瑟夫环"问题: <单循环链表求解约瑟夫环问题(Java语言描述)> <杀人游戏~约瑟夫环(洛谷P1145题题解 ...

  7. 洛谷P2108学英语题解

    来我的博客里拥有更好的阅读体验:https://yyxi.ml/2020/07/23/luogu-p2108-xueyingyu/ 洛谷P2108学英语题解(c++) 题目描述 代码.思路 踩过的坑 ...

  8. 洛谷 P1077 摆花 题解

    洛谷 P1077 摆花 题解 洛谷 P1077 题目 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共mmm盆.通过调查顾客的喜好,小明列出了顾客最喜欢的nnn种花,从1到nnn标号.为 ...

  9. 【bzoj1565】[NOI2009]植物大战僵尸 【网络流】【最大权闭合子图】

    题解:可以看出每个格子有一些前驱,只有前驱都被消灭了才能走到这里.因为要求最大的权值和,所以我们可以用最大权闭合子图来求解这题.最大权闭合子图点这里! 然后让蒟蒻讲一讲自己掉的坑. 首先,根据WYC大 ...

最新文章

  1. C语言内存管理-字符数组与字符指针
  2. 《锋利的jQuery》学习---基础篇01(持续更新)
  3. 计算机主机箱前后都有什么,目前四种热门的主机机箱设计都有哪些优缺点?
  4. es6 Class 的 Generator函数
  5. Redraiment猜想----米勒拉宾+分块打表
  6. Python requests抓取有道翻译 最新版破解js加密
  7. Java高级工程师技能要求参考
  8. linux安装文泉驿字体,文泉驿的安装及配置
  9. 2021牛客多校第十场补题 F-Train Wreck
  10. python 录屏_《自拍教程70》Python adb一键录屏
  11. cadence导入dxf文件_PCB原创|cadence allegro导入DXF文件操作步骤
  12. 苹果高管参与直播,或将发布新品
  13. 大数据 | Hadoop性能测试
  14. 计算机上如何转换搜狗,无法切换到搜狗输入法怎么办
  15. 自定义菜单 微信公众平台开发教程(2)
  16. 日本西历和和历的转换(转)
  17. 一键seo提交收录_SEO学习的作用,及SEO学习操作步骤!
  18. Python3 借助pywin32模块获取Windows当前和所有窗口正在运行的应用程序信息
  19. 外链html怎么添加,网站外链添加如何来做,要注意这些原则
  20. 我的世界mod整合包java_我的世界1.10.2mod大全+整合包+合集

热门文章

  1. 前端工程师面试经验导图
  2. 数据库优化:优化查询
  3. sql 数据分组统计与合计
  4. git怎么操作会丢失自己的代码_git找回丢失的代码
  5. 嵌入式Linux入门3:Linux服务器搭建
  6. 通过iframe搭建后台管理系统右侧内容_七巧Plus | 搭建量身定制的EAM资产管理系统...
  7. 【Flink】Flink SQL 自定义 Source format
  8. 【Flink】Flink 1.9 升级 到 flink 1.12.4 报错 flink.client.cli.AbstractCustomCommandLine <init>
  9. 【Redis】Redis 五大基本数据类型
  10. 【Es】ElasticSearch 自定义分词器