https://www.luogu.org/problemnew/show/P4174

最大权闭合子图的模板

每个通讯站建一个点,点权为-Pi;每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连边;然后就可以跑了

方法是:

建新源S和新汇T,从S向所有正权点连边,容量为点权值;从所有负权点向T连边,容量为点权值的相反数;原图中所有边容量设为无穷大

跑S到T最大流

原因:(网上都有,自己研究的也不知道有没有偏差)

找出图的任意一个割,其中:

显然不可能割掉容量为无穷大的边;

割掉一条S到u的边,表示不取点u,同时舍弃u点的价值;

割掉一条v到T的边,表示取点v,同时加上v点的代价;

能保证割完这个割中的边后,S到T不连通,即保证不存在任意路径,从S到u经过一些点到v再到T,即保证不存在一个u点需要被取,但是它能到达的一个节点v没有被取。

因此,一个割对应一种闭合子图方案

同样的,可以证明一种闭合子图方案一定对应这样的一个割。

那么,求出最小割,就求出了最小的"舍弃的价值和"+"加上的代价和",设其为x,则最大权闭合子图的点权和等于所有正点权和-x,而最小割等于最大流

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<vector>
  5. #include<queue>
  6. using namespace std;
  7. #define fi first
  8. #define se second
  9. #define mp make_pair
  10. #define pb push_back
  11. typedef long long ll;
  12. typedef unsigned long long ull;
  13. typedef pair<int,int> pii;
  14. namespace F
  15. {
  16.  
  17. struct E
  18. {
  19. int to,nxt,from,cap,flow;
  20. }e[];
  21. int f1[],ne=;
  22. int S,T,n;
  23. int d[];
  24. bool bfs()
  25. {
  26. int k,u;
  27. memset(d,,sizeof(int)*(n+));
  28. queue<int> q;
  29. q.push(S);d[S]=;
  30. while(!q.empty())
  31. {
  32. u=q.front();q.pop();
  33. for(k=f1[u];k;k=e[k].nxt)
  34. if(!d[e[k].to]&&e[k].cap>e[k].flow)
  35. {
  36. d[e[k].to]=d[u]+;
  37. //if(e[k].to==T) return 1;
  38. q.push(e[k].to);
  39. }
  40. }
  41. //return 0;
  42. return d[T];
  43. }
  44. int cur[];
  45. int dfs(int u,int x)
  46. {
  47. if(u==T||x==) return x;
  48. int flow=,f;
  49. for(int &k=cur[u];k;k=e[k].nxt)
  50. if(e[k].cap>e[k].flow&&d[e[k].to]==d[u]+)
  51. {
  52. f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
  53. e[k].flow+=f;e[k^].flow-=f;flow+=f;
  54. if(flow==x) return flow;
  55. }
  56. return flow;
  57. }
  58. int solve()
  59. {
  60. int flow=;
  61. while(bfs())
  62. {
  63. memcpy(cur,f1,sizeof(int)*(n+));
  64. flow+=dfs(S,0x3f3f3f3f);
  65. }
  66. return flow;
  67. }
  68. void me(int a,int b,int c)
  69. {
  70. e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
  71. e[ne].from=a;e[ne].cap=c;
  72. e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
  73. e[ne].from=b;e[ne].cap=;
  74. }
  75.  
  76. }
  77. int n,m;
  78. int main()
  79. {
  80. int i,a,b,c,ss=,t;
  81. scanf("%d%d",&n,&m);F::n=n+m+;F::S=n+m+;F::T=n+m+;
  82. for(i=;i<=n;i++)
  83. {
  84. scanf("%d",&t);
  85. F::me(i,F::T,t);
  86. //ss-=t;
  87. }
  88. for(i=;i<=m;i++)
  89. {
  90. scanf("%d%d%d",&a,&b,&c);
  91. F::me(F::S,i+n,c);
  92. F::me(i+n,a,0x3f3f3f3f);
  93. F::me(i+n,b,0x3f3f3f3f);
  94. ss+=c;
  95. }
  96. printf("%d",ss-F::solve());
  97. return ;
  98. }

upd20190307:

貌似cf出了重题,但是要改longlonghttps://codeforces.com/problemset/problem/1082/G


https://www.luogu.org/problemnew/show/P2762

这题也是一样,但是要输出方案

按照上面的方法,只要找出任意一组最小割就容易找到输出方法了

怎么找最小割?只要找出跑出最大流以后,找出残量网络中源点S能到达的点集s1,取t1=所有点的集合-s1,那么割掉原图中所有s1,t1间的边即可

这里面有一个看起来比较靠谱的证明:https://hihocoder.com/problemset/problem/1378

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<vector>
  5. #include<queue>
  6. #include<iostream>
  7. using namespace std;
  8. #define fi first
  9. #define se second
  10. #define mp make_pair
  11. #define pb push_back
  12. typedef long long ll;
  13. typedef unsigned long long ull;
  14. typedef pair<int,int> pii;
  15. namespace F
  16. {
  17.  
  18. struct E
  19. {
  20. int to,nxt,from,cap,flow;
  21. }e[];
  22. int f1[],ne=;
  23. int S,T,n;
  24. int d[];
  25. bool bfs()
  26. {
  27. int k,u;
  28. memset(d,,sizeof(int)*(n+));
  29. queue<int> q;
  30. q.push(S);d[S]=;
  31. while(!q.empty())
  32. {
  33. u=q.front();q.pop();
  34. for(k=f1[u];k;k=e[k].nxt)
  35. if(!d[e[k].to]&&e[k].cap>e[k].flow)
  36. {
  37. d[e[k].to]=d[u]+;
  38. //if(e[k].to==T) return 1;
  39. q.push(e[k].to);
  40. }
  41. }
  42. //return 0;
  43. return d[T];
  44. }
  45. int cur[];
  46. int dfs(int u,int x)
  47. {
  48. if(u==T||x==) return x;
  49. int flow=,f;
  50. for(int &k=cur[u];k;k=e[k].nxt)
  51. if(e[k].cap>e[k].flow&&d[e[k].to]==d[u]+)
  52. {
  53. f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
  54. e[k].flow+=f;e[k^].flow-=f;flow+=f;
  55. if(flow==x) return flow;
  56. }
  57. return flow;
  58. }
  59. int solve()
  60. {
  61. int flow=;
  62. while(bfs())
  63. {
  64. memcpy(cur,f1,sizeof(int)*(n+));
  65. flow+=dfs(S,0x3f3f3f3f);
  66. }
  67. return flow;
  68. }
  69. void me(int a,int b,int c)
  70. {
  71. e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
  72. e[ne].from=a;e[ne].cap=c;
  73. e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
  74. e[ne].from=b;e[ne].cap=;
  75. }
  76.  
  77. }
  78.  
  79. int n,m;
  80. char tools[];
  81. bool ok[];
  82. int tt[];
  83. void work()
  84. {
  85. int k,u;
  86. memset(ok,,sizeof(bool)*(n+));
  87. queue<int> q;
  88. q.push(F::S);ok[F::S]=;
  89. using F::f1;using F::e;
  90. while(!q.empty())
  91. {
  92. u=q.front();q.pop();
  93. for(k=f1[u];k;k=e[k].nxt)
  94. if(!ok[e[k].to]&&e[k].cap>e[k].flow)
  95. {
  96. q.push(e[k].to);
  97. ok[e[k].to]=;
  98. }
  99. }
  100. for(int i=;i<=F::n;i++)
  101. if(ok[i])
  102. {
  103. for(k=f1[i];k;k=e[k].nxt)
  104. if(k%==&&!ok[e[k].to])
  105. tt[++tt[]]=k;
  106. }
  107. }
  108. bool nok[];
  109. int main()
  110. {
  111. int i,a,b,c,ss=,t;
  112. scanf("%d%d",&m,&n);F::n=n+m+;F::S=n+m+;F::T=n+m+;
  113. for(i=;i<=m;i++)
  114. {
  115. scanf("%d",&t);
  116. F::me(F::S,i,t);
  117. ss+=t;
  118. cin.getline(tools,);
  119. int ulen=,tool;
  120. while(sscanf(tools+ulen,"%d",&tool)==)
  121. {
  122. F::me(i,tool+m,0x3f3f3f3f);
  123. if(tool==)
  124. ulen++;
  125. else
  126. {
  127. while(tool)
  128. {
  129. tool/=;
  130. ulen++;
  131. }
  132. }
  133. ulen++;
  134. }
  135. }
  136. for(i=;i<=n;i++)
  137. {
  138. scanf("%d",&t);
  139. F::me(i+m,F::T,t);
  140. }
  141. int an=ss-F::solve();
  142. work();
  143. for(i=;i<=tt[];i++)
  144. {
  145. using F::e;
  146. if(e[tt[i]].from==F::S)
  147. {
  148. nok[e[tt[i]].to]=;
  149. }
  150. }
  151. for(i=;i<=m;i++)
  152. if(!nok[i])
  153. printf("%d ",i);
  154. puts("");
  155. for(i=;i<=tt[];i++)
  156. {
  157. using F::e;
  158. if(e[tt[i]].to==F::T)
  159. {
  160. printf("%d ",e[tt[i]].from-m);
  161. }
  162. }
  163. puts("");
  164. printf("%d",an);
  165. return ;
  166. }

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

  1. 洛谷P2762 太空飞行计划问题(最大权闭合图)

    题意 有$m$个实验,$n$中器材,每个实验需要使用一些器材 每个实验有收入,每个器材有花费 最大化收入 - 花费 Sol 最大权闭合图的经典应用 从$S$向每个实验连流量为该实验收入的边 从每个器材 ...

  2. 【最大权闭合子图 最小割】bzoj1497: [NOI2006]最大获利

    最大权闭合子图的模型:今天才发现dinic板子是一直挂的…… Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在 ...

  3. 洛谷 P2762 太空飞行计划问题 【最大权闭合子图+最小割】

    --一道难在读入的题. 最后解决方案直接getline一行然后是把读优拆掉放进函数,虽然很丑但是过了. 然后就是裸的最大权闭合子图了,把仪器当成负权点向t连流量为其价格的边,s向实验连流量为实验报酬的 ...

  4. bzoj 1497 [NOI2006]最大获利【最大权闭合子图+最小割】

    不要被5s时限和50000点数吓倒!大胆网络流!我一个5w级别的dinic只跑了1s+! 看起来没有最大权闭合子图的特征--限制,实际上还是有的. 我们需要把中转站看成负权点,把p看成点权,把客户看成 ...

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

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

  6. 洛谷 P4174 [NOI2006]最大获利 解题报告

    P4174 [NOI2006]最大获利 题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要 ...

  7. 洛谷P4174 [NOI2006]最大获利(最大流)

    题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需 ...

  8. [洛谷P4174][NOI2006]最大获利

    题目大意:同Petya and Graph,数据范围改成$n\leqslant5\times10^3,m\leqslant5\times10^4$ 题解:同上 卡点:无 C++ Code: #incl ...

  9. 洛谷 [P2762] 太空飞行计划问题

    最大权闭合子图 胡伯涛论文真是个好东西.jpg 求一个有向图的最大权闭合子图,常应用于有先决条件的最优化问题中 将所有正权点与源点相连,容量为点权; 将所有负权点与汇点相连,容量为点权的相反数; 将原 ...

随机推荐

  1. php-get和post请求

    1.get请求 <?php //判断20130101是否是工作日 //工作日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2: $url='http://www.easybots ...

  2. Local storage htm5

    使用本地存储,web应用可以在用户浏览器中本地存储数据. 在HTML5之前,应用数据存储必须使用cookie,包括每个服务端的请求,本地存储更加安全,并且可以存储大量的数据到本地,不影响网站的性能. ...

  3. C语言system()函数:执行shell命令

    头文件:#include <stdlib.h> 定义函数:int system(const char * string); 函数说明:system()会调用fork()产生子进程, 由子进 ...

  4. Rsyslog 日志相关内容

    [root@server vusers_home]# rpm -ql rsyslog|more       ###.so结尾为模块,模块有分im为输入模块,om 为输出模块/etc/logrotate ...

  5. Update 出现在的问题

    报错提示:之前的操作没有完成,运行deanup被打断,请先执行Cleanup方法. 正常右键点击Cleanup,如果只让默认值勾选,可能还是会报这个错.所以正确操作如下: 全部选中再点击OK,这样就可 ...

  6. 微信小程序内嵌网页能力开放 小程序支持内嵌网页文档说明

    为了方便开发者灵活配置微信小程序,张小龙现在开放了小程序的内嵌网页功能,这是一个非常大的惊喜啊,以后意味着你只要开放一个手机端网站,就可以制作一个小程序了哦.操作方法1.开发者登录微信小程序后台,选择 ...

  7. Spring Boot配置多个DataSource

    使用Spring Boot时,默认情况下,配置DataSource非常容易.Spring Boot会自动为我们配置好一个DataSource. 百牛信息技术bainiu.ltd整理发布于博客园 如果在 ...

  8. ftp主要流程

    判断是否是root用户,若不是则提示并退出. 建立server socket. 等待用户连接,并建立相应用户的子进程.

  9. Ubuntu 16.04使用chrome闪屏

    使用Chrome的时候上端经常出现闪动的情况, 但是速度特别快, 根本无法截图, 感觉特别扎心, 以为自己的电脑出现问题了或者显卡驱动出现问题了, 后来才发现问题, 只需要关闭Chrome的硬件加速就 ...

  10. js正则匹配字符串

    这里我第一时间想到的就是用 js 的search 和 match ,其中最常见的是match: 1. str.search(regexp):search()方法不支持全局搜索,因为会忽略正则表达式参数 ...