POJ 2987 Firing(最大流最小割の最大权闭合图)
Description
You’ve finally got mad at “the world’s most stupid” employees of yours and decided to do some firings. You’re now simply too mad to give response to questions like “Don’t you think it is an even more stupid decision to have signed them?”, yet calm enough to consider the potential profit and loss from firing a good portion of them. While getting rid of an employee will save your wage and bonus expenditure on him, termination of a contract before expiration costs you funds for compensation. If you fire an employee, you also fire all his underlings and the underlings of his underlings and those underlings’ underlings’ underlings… An employee may serve in several departments and his (direct or indirect) underlings in one department may be his boss in another department. Is your firing plan ready now?
Input
The input starts with two integers n (0 < n ≤ 5000) and m (0 ≤ m ≤ 60000) on the same line. Next follows n + m lines. The first n lines of these give the net profit/loss from firing the i-th employee individually bi (|bi| ≤ 107, 1 ≤ i ≤ n). The remaining m lines each contain two integers i and j (1 ≤ i, j ≤ n) meaning the i-th employee has the j-th employee as his direct underling.
Output
Output two integers separated by a single space: the minimum number of employees to fire to achieve the maximum profit, and the maximum profit.
题目大意:有n个点,每个点有一个权值(可能为负数),有m条有向边,求一个闭合子图,要求在权值最大的情况下点最少。
PS:所谓闭合子图,即在一个图中,若选择了x,那么x的所有后继都要选上(如a→b→c→d→e,选了b,就要选c、d、e)。
思路:最大权闭合图的经典建图:源点S到所有正权的点连一条边,容量为权值,从所有负权的点连一条边到汇点T,容量为权值的绝对值。对每一条边(i, j),连一条边i→j,容量为无穷大。所有正权权值之和减去最大流(最小割)为最大权,从S遍历一遍残量网络,能遍历到的点都为闭合子图中的点,计数即可得到答案。
小证明:在残量网络中,S能遍历到的点都为所选闭合子图,记为V(s),其余记为V(T)。那么V(S)中任何一个点,它都不会有容量为无穷大的边会指向V(T)中的点,因为若有,这条边要算入最小割,而最小割不可能为无穷大,这就保证了选了点x,x的后继都会被选上。记sum为所有正权权值之和,一个简单割(不割无穷大的边)割掉的与S关联的边的容量和为cut(S),割掉的与T关联的边的容量和为cut(T),对于所有选上的点,与源点关联的点的权和应该为sum - cut(S),cut(S)都是没有选上的点;与汇点关联的选上的点的权和为cut(T),cut(T)都是选上的点。那么该子图的权和为sum - cut(S) - cut(T),即sum - (cut(S) + cut(T)),我们需要最大化前面的式子,而sum是固定值,所以需要最小化cut(S) + cut(T),这个值最小的时候,就是最小割。
关于这样选到的点一定是最少的证明可以看下面的链接,不过简单地说就是:若有多种选择,那么就有一片点,选上它们之后权值总和为0,也就是源点到它们的容量应该是满的,因为我们是在残量网络中遍历,所以它们绝对不会被遍历到。至于下面链接所说的原图是DAG,这个我没看出来哪里说了……不过我们可以把环缩成一个点,不影响证明……
http://hi.baidu.com/dispossessed/item/f75d32161ae2d8573a176e8d
代码(391MS):
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; typedef long long LL; const int MAXN = ;
const int MAXE = ;
const LL INF = 0x3fff3fff3fff3fffLL; struct SAP {
int head[MAXN], dis[MAXN], gap[MAXN], cur[MAXN], pre[MAXN];
int to[MAXE], next[MAXE];
LL flow[MAXE];
int ecnt, n, st, ed; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, LL c) {
to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; flow[ecnt] = ; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d->%d %I64d\n", u, v, c);
} void bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<int> que; que.push(ed);
dis[ed] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
++gap[dis[u]];
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p ^ ] && dis[v] > n) {
dis[v] = dis[u] + ;
que.push(v);
}
}
}
} LL Max_flow(int ss, int tt, int nn) {
st = ss; ed = tt; n = nn;
LL ans = , minFlow = INF;
for(int i = ; i <= n; ++i) {
cur[i] = head[i];
gap[i] = ;
}
int u = pre[st] = st;
bfs();
while(dis[st] < n) {
bool flag = false;
for(int &p = cur[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && dis[u] == dis[v] + ) {
flag = true;
minFlow = min(minFlow, flow[p]);
pre[v] = u;
u = v;
if(u == ed) {
ans += minFlow;
while(u != st) {
u = pre[u];
flow[cur[u]] -= minFlow;
flow[cur[u] ^ ] += minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && dis[v] < minDis) {
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == ) break;
++gap[dis[u] = minDis + ];
u = pre[u];
}
return ans;
} int cnt_S() {
memset(dis, , sizeof(dis));
int * vis = dis, ret = ;
queue<int> que; que.push(st);
vis[st] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && !vis[v]) {
vis[v] = ;
++ret;
que.push(v);
}
}
}
return ret;
}
} G; int main() {
int n, m, a, b;
LL x, sum = ;
scanf("%d%d", &n, &m);
int ss = , tt = n + ;
G.init();
for(int i = ; i <= n; ++i) {
scanf("%I64d", &x);
if(x > ) sum += x, G.add_edge(ss, i, x);
if(x < ) G.add_edge(i, tt, -x);
}
for(int i = ; i <= m; ++i) {
scanf("%d%d", &a, &b);
G.add_edge(a, b, INF);
}
LL ans1 = sum - G.Max_flow(ss, tt, tt);
int ans2 = G.cnt_S();
printf("%d %I64d\n", ans2, ans1);
}
POJ 2987 Firing(最大流最小割の最大权闭合图)的更多相关文章
- 【BZOJ-3438】小M的作物 最小割 + 最大权闭合图
3438: 小M的作物 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 825 Solved: 368[Submit][Status][Discuss ...
- 【POJ 2987】Firing (最小割-最大权闭合子图)
裁员 [问题描述] 在一个公司里,老板发现,手下的员工很多都不务正业,真正干事员工的没几个,于是老板决定大裁员,每开除一个人,同时要将其下属一并开除,如果该下属还有下属,照斩不误.给出每个人的贡献值和 ...
- POJ 2987 Firing【最大权闭合图-最小割】
题意:给出一个有向图,选择一个点,则要选择它的可以到达的所有节点.选择每个点有各自的利益或损失.求最大化的利益,以及此时选择人数的最小值. 算法:构造源点s汇点t,从s到每个正数点建边,容量为利益.每 ...
- poj 2987 Firing 最大权闭合图
题目链接:http://poj.org/problem?id=2987 You’ve finally got mad at “the world’s most stupid” employees of ...
- POJ 2987:Firing(最大权闭合图)
http://poj.org/problem?id=2987 题意:有公司要裁员,每裁一个人可以得到收益(有正有负),而且如果裁掉的这个人有党羽的话,必须将这个人的所有党羽都裁除,问最少的裁员人数是多 ...
- POJ 2987 Firing(最大权闭合图)
[题目链接] http://poj.org/problem?id=2987 [题目大意] 为了使得公司效率最高,因此需要进行裁员, 裁去不同的人员有不同的效率提升效果,当然也有可能是负的效果, 如果裁 ...
- POJ 2987 Firing 网络流 最大权闭合图
http://poj.org/problem?id=2987 https://blog.csdn.net/u014686462/article/details/48533253 给一个闭合图,要求输出 ...
- poj 2987(最大权闭合图+割边最少)
题目链接:http://poj.org/problem?id=2987 思路:标准的最大权闭合图,构图:从源点s向每个正收益点连边,容量为收益:从每个负收益点向汇点t连边,容量为收益的相反数:对于i是 ...
- poj 2987 最大权闭合图
Language: Default Firing Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 8744 Accept ...
随机推荐
- Redis与Python进行交互
安装包 安装Redis的有3种方式https://github.com/andymccurdy/redis-py 第一种:进⼊虚拟环境,联⽹安装包redis pip install redis 第二种 ...
- 解决h5底部输入框在ios被软键盘顶飞 软键盘消失还下不来
好吧,其实不是顶飞,准确点说应该是h5页面fiexed定位在底部的输入框在ios软键盘弹起的时候软键盘跟输入框有时会有一段悬空的距离,无法紧贴.在安卓机子上则没有这样的情况. 解决方法是通过h5的sc ...
- thinkphp5 部署到iis服务器url重写
thinkphp部署到iis服务器配置url重写的解决方法: 1.下载 url rewrite.下载地址:https://www.iis.net/downloads/microsoft/url-rew ...
- spark成长之路(1)spark究竟是什么?
今年6月毕业,来到公司前前后后各种事情折腾下来,8月中旬才入职.本以为终于可以静下心来研究技术了,但是又把我分配到了一个几乎不做技术的解决方案部门,导致现在写代码的时间都几乎没有了,所以只能在每天下班 ...
- Drill-On-YARN
1. Drill-On-YARN介绍 功能 启动 停止 扩容 缩容 failover 启动流程 下载drill的社区包,进行必要的配置,执行drill-on-yarn.sh start命令,启动dri ...
- 用Python生成词云
词云以词语为基本单元,根据词语在文本中出现的频率设计不同大小的形状以形成视觉上的不同效果,从而使读者只要“一瞥“即可领略文本的主旨.以下是一个词云的简单示例: import jieba from wo ...
- PAT 1001 害死人不偿命的(3n+1)猜想
1001 害死人不偿命的(3n+1)猜想 (15 分) 卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 (3n+1) 砍掉一半.这样一直反复 ...
- SaltStack error: No module named 'salt'
启动saltstack的时候出现下面的错误 问题原因 是因为我在centos7中安装了多版本的python导致的 解决方案 将文件下面文件首行更改成python2 [root@saltstack-12 ...
- 20145209刘一阳 《网络对抗》Exp7 网络欺诈技术防范
20145209刘一阳 <网络对抗>Exp7 网络欺诈技术防范 一.应用SET工具建立冒名网站 要让冒名网站在别的主机上也能看到,需要开启本机的Apache服务,并且要将Apache服务的 ...
- 使数据可供ArcGIS Server访问
内容来自ESRI官方文档(点击访问),简单总结如下: 1 ArcGIS Server用于发布服务的数据必须存储在服务器可以访问的位置: 2 这样的位置有三种类型: 本地路径:将数据本地存储在每台 Ar ...