题意:给出一个有向图,选择一个点,则要选择它的可以到达的所有节点。选择每个点有各自的利益或损失。求最大化的利益,以及此时选择人数的最小值。

算法:构造源点s汇点t,从s到每个正数点建边,容量为利益。每个负点到t建边,容量为损失的绝对值。其他关系边容量正向无穷,反向0。正数点总和减去最小割即为最大权闭合图答案。因为残余网络不会对0流边处理,所以不会将0流点选入取点集,所以最小割的取法中为被选中的点。

最大权闭合图的求解方法:

  1. 先构造网络流N,添加源点s,从s到正权值点做一条边,容量为点的权值。

  2. 添加汇点t,从负权值点到t做一条边,容量为点的权值的绝对值。

  3. 原来的边的容量统统设为无穷大。比如:

    转换为

  4. 求解最小割:最大权=正权值之和-最小割权值

  5. 残余网络中的点的个数即为裁员个数。

思路:最大权闭合图。用Dinic求最小割

要得到最大收益,就是尽量选择更多收益为正数的人,选择更少收益为负数的人,因此我们将收益为正数的人与源点连一条边,将收益为负数的人与汇点连一条边,这样得到的割集就是未选择的收益为正数的人+选择的收益为负数的人(也可以是损失的收益),要使这个割集越小越好,那么就是求最小割。最大收益是所有正数的和sum,再用sum-最小割(损失的收益)就可以得到最大收益。

最少的裁员人数,最小割后的的残余网络中,只要能从S遍历到的点,就可以看成是被裁掉的点,因为最终肯定会遇到割边达不到T,所以我们直接DFS残余网络的点数就可以得到最少的裁员人数了。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <queue>
  5. #include <vector>
  6. using namespace std;
  7. typedef long long LL;
  8.  
  9. const LL INF = 0x3f3f3f3f3f3f3f3f;
  10.  
  11. struct edge
  12. {
  13. edge(int _v,int _r, LL _c):v(_v),r(_r),c(_c){};
  14. int v,r;
  15. LL c;
  16. };
  17.  
  18. vector<edge> e[];
  19.  
  20. void add_edge(int u,int v,LL c)
  21. {
  22. e[u].push_back(edge(v,e[v].size(),c));
  23. e[v].push_back(edge(u,e[u].size()-,));
  24. }
  25.  
  26. int level[];
  27. int iter[]; // 当前弧,在其之前的边已经没有用了
  28. queue<int> q;
  29.  
  30. bool bfs(int s,int t)
  31. {
  32. memset(level,, sizeof(level));
  33. while (!q.empty()) q.pop();
  34. q.push(s);
  35. level[s]=;
  36. while(!q.empty())
  37. {
  38. int u=q.front();q.pop();
  39. for(int i=;i<e[u].size();i++)
  40. {
  41. int v=e[u][i].v;
  42. if(e[u][i].c>&&!level[v])
  43. {
  44. q.push(v);
  45. level[v]=level[u]+;
  46. }
  47. if(level[t])return ;
  48. }
  49. }
  50. return ;
  51. }
  52.  
  53. LL dfs(int s,int t, LL flow)
  54. {
  55. if(s==t)return flow;
  56. for(int& i = iter[s];i<e[s].size();i++) // 一次增广返回时,记录当前弧
  57. {
  58. int v = e[s][i].v;
  59. if(e[s][i].c>&&level[v]==level[s]+)
  60. {
  61. LL k = dfs(v,t,min(flow,e[s][i].c));
  62. if(k>)
  63. {
  64. e[s][i].c-=k;
  65. e[v][e[s][i].r].c+=k;
  66. return k;
  67. }
  68. }
  69. }
  70. return ;
  71. }
  72.  
  73. LL Dinic(int s,int t)
  74. {
  75. LL flow=;
  76. while(bfs(s,t))
  77. {
  78. LL f=;
  79. memset(iter, , sizeof(iter));
  80. while((f=dfs(s,t,INF))>)flow+=f;
  81. }
  82. return flow;
  83. }
  84.  
  85. bool vis[];
  86. int cnt;
  87. void GaoCnt(int u)//dfs统计残余图的正边
  88. {
  89. ++cnt;
  90. vis[u]=;
  91. for(int i=;i<e[u].size();i++)
  92. {
  93. int v=e[u][i].v;
  94. if(e[u][i].c>&&!vis[v])
  95. GaoCnt(v);
  96. }
  97. }
  98.  
  99. int main()
  100. {
  101. int n,m;
  102. scanf("%d%d",&n,&m);
  103. int s=,t=n+;// 源点,汇点
  104. LL ans=;
  105. for(int i=;i<=n;i++)
  106. {
  107. LL c;
  108. scanf("%lld",&c);
  109. if(c>)
  110. {
  111. ans+=c; //正权值求和
  112. add_edge(s,i,c);
  113. }
  114. else if(c<)
  115. {
  116. add_edge(i,t,-c);
  117. }
  118. }
  119. for (int i = ; i < m; ++i) {
  120. int u,v;
  121. scanf("%d%d",&u,&v);
  122. add_edge(u,v,INF);
  123. }
  124. ans-= Dinic(s,t);
  125. GaoCnt(s);
  126. printf("%d %lld\n",cnt-,ans);
  127. return ;
  128. }

参考自:hankcsyogykwan

POJ 2987 Firing【最大权闭合图-最小割】的更多相关文章

  1. poj 2987 Firing 最大权闭合图

    题目链接:http://poj.org/problem?id=2987 You’ve finally got mad at “the world’s most stupid” employees of ...

  2. [luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)

    传送门 如果将每一个实验和其所对的仪器连一条有向边,那么原图就是一个dag图(有向无环) 每一个点都有一个点权,实验为收益(正数),仪器为花费(负数). 那么接下来可以引出闭合图的概念了. 闭合图是原 ...

  3. POJ 2987 - Firing - [最大权闭合子图]

    题目链接:http://poj.org/problem?id=2987 Time Limit: 5000MS Memory Limit: 131072K Description You’ve fina ...

  4. POJ 2987 Firing | 最大权闭合团

    一个点带权的图,有一些指向关系,删掉一个点他指向的点也不能留下,问子图最大权值 题解: 这是最大权闭合团问题 闭合团:集合内所有点出边指向的点都在集合内 构图方法 1.S到权值为正的点,容量为权值 2 ...

  5. B1391 [Ceoi2008]order 最大权闭合图 最小割

    啊啊啊,假的题吧!!!我用的当前弧优化T了6个点,其他人不用优化AC!!!震惊!!!当前弧优化是假的吧!!! 到现在我也没调出来...大家帮我看看为啥70.... 来讲一下这个题的思路,就是设一个源点 ...

  6. POJ2987 Firing 最大权闭合图

    详情请参考http://www.cnblogs.com/kane0526/archive/2013/04/05/3001557.html 值得注意的地方,割边会把图分成两部分,一部分和起点相连,另一部 ...

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

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

  8. BZOJ 1565 / P2805 [NOI2009]植物大战僵尸 (最大权闭合子图 最小割)

    题意 自己看吧 BZOJ传送门 分析 - 这道题其实就是一些点,存在一些二元限制条件,即如果要选uuu则必须选vvv.求得到的权值最大是多少. 建一个图,如果选uuu必须选vvv,则uuu向vvv连边 ...

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

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

随机推荐

  1. 休眠与开机自动运行等VC代码

    //根据文件句柄,获取文件名 #include <windows.h> #include <stdio.h> #include <tchar.h> #include ...

  2. select2使用方法总结

    官网:http://select2.github.io/ 调用 <link href="~/Content/select2.min.css" rel="styles ...

  3. 【转】C++拷贝构造函数详解

    一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对象拷贝 ...

  4. 修改.bashrc文件PATH变量错误导致系统大部分命令失效

    修改.bashrc环境变量,在文件最后添加openssl变量, 本来应该写 export PATH=$PATH:/usr/local/openssl/bin 误写成 export PATH=/usr/ ...

  5. zookeeper的三种安装模式

    zookeeper的安装分为三种模式:单机模式.集群模式和伪集群模式. 1.单机模式 首先,从Apache官网下载一个Zookeeper稳定版本,本次教程采用的是zookeeper-3.4.9版本. ...

  6. Python-视图 触发器 事务 存储过程

    1.视图2.触发器*** 在某个时间发生了某个事件时 会自动触发一段sql语句3.事务*****4.存储过程***** 5.函数6.备份与恢复*** mysqldump -u -p (库名 [表名] ...

  7. 基于C#net4.5websocket客户端与服务端

    只支持win8以上系统以及windows server2012以上系统 最近在研究视频传输给浏览器,然后使用H5标签解码.视频流采用websocket传输.所以研究了一下C#的websocket. 首 ...

  8. 遇到的一个移动端从下往上过渡的弹框,在Android下过渡动画的优化问题。

    优化之前: /* 分享弹框样式 */ .popUpDiv { width: 100vw; height: 100vh; transition: all 0.5s ease; position: fix ...

  9. Java的动手动脑(七)

    日期:2018.11.18 博客期:025 星期日 Part 1:使用 Files.walkFileTree()来找出指定文件夹下大小大于1KB的文件 package temp; import jav ...

  10. LeetCode(90):子集 II

    Medium! 题目描述: 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1 ...