POJ 2987 Firing【最大权闭合图-最小割】
题意:给出一个有向图,选择一个点,则要选择它的可以到达的所有节点。选择每个点有各自的利益或损失。求最大化的利益,以及此时选择人数的最小值。
算法:构造源点s汇点t,从s到每个正数点建边,容量为利益。每个负点到t建边,容量为损失的绝对值。其他关系边容量正向无穷,反向0。正数点总和减去最小割即为最大权闭合图答案。因为残余网络不会对0流边处理,所以不会将0流点选入取点集,所以最小割的取法中为被选中的点。
最大权闭合图的求解方法:
先构造网络流N,添加源点s,从s到正权值点做一条边,容量为点的权值。
添加汇点t,从负权值点到t做一条边,容量为点的权值的绝对值。
原来的边的容量统统设为无穷大。比如:
转换为
求解最小割:最大权=正权值之和-最小割权值
残余网络中的点的个数即为裁员个数。
思路:最大权闭合图。用Dinic求最小割
要得到最大收益,就是尽量选择更多收益为正数的人,选择更少收益为负数的人,因此我们将收益为正数的人与源点连一条边,将收益为负数的人与汇点连一条边,这样得到的割集就是未选择的收益为正数的人+选择的收益为负数的人(也可以是损失的收益),要使这个割集越小越好,那么就是求最小割。最大收益是所有正数的和sum,再用sum-最小割(损失的收益)就可以得到最大收益。
最少的裁员人数,最小割后的的残余网络中,只要能从S遍历到的点,就可以看成是被裁掉的点,因为最终肯定会遇到割边达不到T,所以我们直接DFS残余网络的点数就可以得到最少的裁员人数了。
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <queue>
- #include <vector>
- using namespace std;
- typedef long long LL;
- const LL INF = 0x3f3f3f3f3f3f3f3f;
- struct edge
- {
- edge(int _v,int _r, LL _c):v(_v),r(_r),c(_c){};
- int v,r;
- LL c;
- };
- vector<edge> e[];
- void add_edge(int u,int v,LL c)
- {
- e[u].push_back(edge(v,e[v].size(),c));
- e[v].push_back(edge(u,e[u].size()-,));
- }
- int level[];
- int iter[]; // 当前弧,在其之前的边已经没有用了
- queue<int> q;
- bool bfs(int s,int t)
- {
- memset(level,, sizeof(level));
- while (!q.empty()) q.pop();
- q.push(s);
- level[s]=;
- while(!q.empty())
- {
- int u=q.front();q.pop();
- for(int i=;i<e[u].size();i++)
- {
- int v=e[u][i].v;
- if(e[u][i].c>&&!level[v])
- {
- q.push(v);
- level[v]=level[u]+;
- }
- if(level[t])return ;
- }
- }
- return ;
- }
- LL dfs(int s,int t, LL flow)
- {
- if(s==t)return flow;
- for(int& i = iter[s];i<e[s].size();i++) // 一次增广返回时,记录当前弧
- {
- int v = e[s][i].v;
- if(e[s][i].c>&&level[v]==level[s]+)
- {
- LL k = dfs(v,t,min(flow,e[s][i].c));
- if(k>)
- {
- e[s][i].c-=k;
- e[v][e[s][i].r].c+=k;
- return k;
- }
- }
- }
- return ;
- }
- LL Dinic(int s,int t)
- {
- LL flow=;
- while(bfs(s,t))
- {
- LL f=;
- memset(iter, , sizeof(iter));
- while((f=dfs(s,t,INF))>)flow+=f;
- }
- return flow;
- }
- bool vis[];
- int cnt;
- void GaoCnt(int u)//dfs统计残余图的正边
- {
- ++cnt;
- vis[u]=;
- for(int i=;i<e[u].size();i++)
- {
- int v=e[u][i].v;
- if(e[u][i].c>&&!vis[v])
- GaoCnt(v);
- }
- }
- int main()
- {
- int n,m;
- scanf("%d%d",&n,&m);
- int s=,t=n+;// 源点,汇点
- LL ans=;
- for(int i=;i<=n;i++)
- {
- LL c;
- scanf("%lld",&c);
- if(c>)
- {
- ans+=c; //正权值求和
- add_edge(s,i,c);
- }
- else if(c<)
- {
- add_edge(i,t,-c);
- }
- }
- for (int i = ; i < m; ++i) {
- int u,v;
- scanf("%d%d",&u,&v);
- add_edge(u,v,INF);
- }
- ans-= Dinic(s,t);
- GaoCnt(s);
- printf("%d %lld\n",cnt-,ans);
- return ;
- }
POJ 2987 Firing【最大权闭合图-最小割】的更多相关文章
- poj 2987 Firing 最大权闭合图
题目链接:http://poj.org/problem?id=2987 You’ve finally got mad at “the world’s most stupid” employees of ...
- [luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)
传送门 如果将每一个实验和其所对的仪器连一条有向边,那么原图就是一个dag图(有向无环) 每一个点都有一个点权,实验为收益(正数),仪器为花费(负数). 那么接下来可以引出闭合图的概念了. 闭合图是原 ...
- POJ 2987 - Firing - [最大权闭合子图]
题目链接:http://poj.org/problem?id=2987 Time Limit: 5000MS Memory Limit: 131072K Description You’ve fina ...
- POJ 2987 Firing | 最大权闭合团
一个点带权的图,有一些指向关系,删掉一个点他指向的点也不能留下,问子图最大权值 题解: 这是最大权闭合团问题 闭合团:集合内所有点出边指向的点都在集合内 构图方法 1.S到权值为正的点,容量为权值 2 ...
- B1391 [Ceoi2008]order 最大权闭合图 最小割
啊啊啊,假的题吧!!!我用的当前弧优化T了6个点,其他人不用优化AC!!!震惊!!!当前弧优化是假的吧!!! 到现在我也没调出来...大家帮我看看为啥70.... 来讲一下这个题的思路,就是设一个源点 ...
- POJ2987 Firing 最大权闭合图
详情请参考http://www.cnblogs.com/kane0526/archive/2013/04/05/3001557.html 值得注意的地方,割边会把图分成两部分,一部分和起点相连,另一部 ...
- 洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
https://www.luogu.org/problemnew/show/P4174 最大权闭合子图的模板 每个通讯站建一个点,点权为-Pi:每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连 ...
- BZOJ 1565 / P2805 [NOI2009]植物大战僵尸 (最大权闭合子图 最小割)
题意 自己看吧 BZOJ传送门 分析 - 这道题其实就是一些点,存在一些二元限制条件,即如果要选uuu则必须选vvv.求得到的权值最大是多少. 建一个图,如果选uuu必须选vvv,则uuu向vvv连边 ...
- 【最大权闭合子图 最小割】bzoj1497: [NOI2006]最大获利
最大权闭合子图的模型:今天才发现dinic板子是一直挂的…… Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在 ...
随机推荐
- 休眠与开机自动运行等VC代码
//根据文件句柄,获取文件名 #include <windows.h> #include <stdio.h> #include <tchar.h> #include ...
- select2使用方法总结
官网:http://select2.github.io/ 调用 <link href="~/Content/select2.min.css" rel="styles ...
- 【转】C++拷贝构造函数详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对象拷贝 ...
- 修改.bashrc文件PATH变量错误导致系统大部分命令失效
修改.bashrc环境变量,在文件最后添加openssl变量, 本来应该写 export PATH=$PATH:/usr/local/openssl/bin 误写成 export PATH=/usr/ ...
- zookeeper的三种安装模式
zookeeper的安装分为三种模式:单机模式.集群模式和伪集群模式. 1.单机模式 首先,从Apache官网下载一个Zookeeper稳定版本,本次教程采用的是zookeeper-3.4.9版本. ...
- Python-视图 触发器 事务 存储过程
1.视图2.触发器*** 在某个时间发生了某个事件时 会自动触发一段sql语句3.事务*****4.存储过程***** 5.函数6.备份与恢复*** mysqldump -u -p (库名 [表名] ...
- 基于C#net4.5websocket客户端与服务端
只支持win8以上系统以及windows server2012以上系统 最近在研究视频传输给浏览器,然后使用H5标签解码.视频流采用websocket传输.所以研究了一下C#的websocket. 首 ...
- 遇到的一个移动端从下往上过渡的弹框,在Android下过渡动画的优化问题。
优化之前: /* 分享弹框样式 */ .popUpDiv { width: 100vw; height: 100vh; transition: all 0.5s ease; position: fix ...
- Java的动手动脑(七)
日期:2018.11.18 博客期:025 星期日 Part 1:使用 Files.walkFileTree()来找出指定文件夹下大小大于1KB的文件 package temp; import jav ...
- LeetCode(90):子集 II
Medium! 题目描述: 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1 ...