http://poj.org/problem?id=2987

题意:有公司要裁员,每裁一个人可以得到收益(有正有负),而且如果裁掉的这个人有党羽的话,必须将这个人的所有党羽都裁除,问最少的裁员人数是多少和最大收益是多少。

思路:有依赖关系,最大权闭合图。我们要得到最大收益,那么就是尽量选择更多收益为正数的人,选择更少收益为负数的人,因此我们将收益为正数的人与源点连一条边,将收益为负数的人与汇点连一条边,这样得到的割集就是未选择的收益为正数的人+选择的收益为负数的人(也可以是损失的收益),很明显答案要使这个割集越小越好,那么就是求最小割。我们能够得到的最大收益是所有正数的和sum,我们再用sum-最小割(损失的收益)就可以得到最大收益了。

至于最少的裁员人数,我也挺迷糊的。看到别人的“将从S出发能到达的点看做firing的集合中的点,其他的能到T的点看作不被firing的集合中的点,那么在做完最大流之后自然就不会有firing集合中的点指向不被firing的集合中的点的边了,否则就会形成增广路。”这句话后,似乎我们只要在最终的残余网络中,只要能从S遍历到的点,就可以看成是被裁掉的点,因为最终肯定会遇到割边达不到T,所以我们直接DFS残余网络的点数就可以得到最少的裁员人数了。

 #include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 5010
#define INF 0x3f3f3f3f
typedef long long LL;
struct Edge {
int v, nxt, cap;
} edge[];
int head[N], cur[N], dis[N], pre[N], gap[N], vis[N], S, T, tot; void Add(int u, int v, int cap) {
edge[tot] = (Edge) {v, head[u], cap}; head[u] = tot++;
edge[tot] = (Edge) {u, head[v], }; head[v] = tot++;
} int BFS() {
memset(dis, INF, sizeof(dis));
memset(gap, , sizeof(gap));
queue<int> que; que.push(T);
dis[T] = ; gap[]++;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(dis[v] < INF) continue;
dis[v] = dis[u] + ;
gap[dis[v]]++;
que.push(v);
}
}
} LL ISAP(int n) {
BFS();
memcpy(cur, head, sizeof(cur));
int u = pre[S] = S, i, flow, index; LL ans = ;
while(dis[S] < n) {
if(u == T) {
flow = INF;
for(i = S; i != T; i = edge[cur[i]].v)
if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i;
for(i = S; i != T; i = edge[cur[i]].v)
edge[cur[i]].cap -= flow, edge[cur[i]^].cap += flow;
u = index; ans += flow;
}
for(i = cur[u]; ~i; i = edge[i].nxt) if(edge[i].cap > && dis[edge[i].v] + == dis[u]) break;
if(~i) {
cur[u] = i; pre[edge[i].v] = u; u = edge[i].v;
} else {
int md = n + ;
if(--gap[dis[u]] == ) break;
for(i = head[u]; ~i; i = edge[i].nxt)
if(edge[i].cap > && dis[edge[i].v] < md) md = dis[edge[i].v], cur[u] = i;
gap[dis[u] = md + ]++;
u = pre[u];
}
}
return ans;
} int DFS(int u) {
vis[u] = ; int ans = ;
for(int i = head[u]; ~i; i = edge[i].nxt)
if(edge[i].cap > && !vis[edge[i].v]) ans += DFS(edge[i].v);
return ans;
} int main() {
int n, m;
while(~scanf("%d%d", &n, &m)) {
S = , T = n + ;
LL sum = ; int u, v; tot = ;
memset(head, -, sizeof(head));
memset(vis, , sizeof(vis));
for(int i = ; i <= n; i++) {
int w; scanf("%d", &w);
if(w > ) Add(S, i, w), sum += w;
else Add(i, T, -w);
}
for(int i = ; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
Add(u, v, INF);
}
LL ans = ISAP(T + );
int res = DFS(S);
printf("%d %lld\n", --res, sum - ans);
}
return ;
}

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. POJ 2987 - Firing - [最大权闭合子图]

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

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

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

  4. POJ2987 Firing 最大权闭合图

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

  5. POJ 2987 Firing 网络流 最大权闭合图

    http://poj.org/problem?id=2987 https://blog.csdn.net/u014686462/article/details/48533253 给一个闭合图,要求输出 ...

  6. POJ 2987 Firing(最大权闭合图)

    [题目链接] http://poj.org/problem?id=2987 [题目大意] 为了使得公司效率最高,因此需要进行裁员, 裁去不同的人员有不同的效率提升效果,当然也有可能是负的效果, 如果裁 ...

  7. POJ 2987 Firing(最大流最小割の最大权闭合图)

    Description You’ve finally got mad at “the world’s most stupid” employees of yours and decided to do ...

  8. POJ 2987 Firing【最大权闭合图-最小割】

    题意:给出一个有向图,选择一个点,则要选择它的可以到达的所有节点.选择每个点有各自的利益或损失.求最大化的利益,以及此时选择人数的最小值. 算法:构造源点s汇点t,从s到每个正数点建边,容量为利益.每 ...

  9. poj 2987(最大权闭合图+割边最少)

    题目链接:http://poj.org/problem?id=2987 思路:标准的最大权闭合图,构图:从源点s向每个正收益点连边,容量为收益:从每个负收益点向汇点t连边,容量为收益的相反数:对于i是 ...

随机推荐

  1. 精装友好联络算法实现借壳和RI

    精装友好联络会 注册算法分析: 1.  许可证由三部分组成. 2. 的登记号的第一部分是顺序编号0x6d模 3. 登记代码的第二部分: 先将订单号与0XB25F1异或,将异或后的结果转换成十进制字符串 ...

  2. Java Class SecurityManager

    # 前言 简单了解 SecurityManager.具体查阅 API. # What 它是 Java 沙盒模型控制安全的重要一个环节.它是 Java 的一个类.下面一段话源于SecurityManag ...

  3. Win10 如何以管理员身份设置开机自启程序(1)

    原文:Win10 如何以管理员身份设置开机自启程序(1) 最近一个项目在win10上部署时遇到问题,即如何设置以管理员身份开机自启.现把解决方法整理如下: 首先,为了进行验证,我编了一个简单的程序te ...

  4. python socket 客服端服务端编程

    客服端编程 import socket try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error a ...

  5. php 二维数组key初始化从0开始

    这个是一个二维数组 array(2) { [1]=> array(2) { ["sourcesid"]=> int(1) ["addusernum" ...

  6. php如何去掉二维数组中重复的元素

    $arr=array( "1"=>array("a","b "), "2"=>array("a&q ...

  7. Ubuntu设置MySQL允许远程访问

    1.注释bind-address = 127.0.0.1. 代码如下: > sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 将bind-address = ...

  8. 没有安装提供程序“System.Data.SqlServerCe.3.5”的解决方法

    在Windows 8.1系统下运行带数据库功能的应用,报错并提示:“System.InvalidOperationException”类型的未经处理的异常在 System.Data.Linq.dll ...

  9. PING[ARC2]: Heartbeat failed to connect to standby 'gqtzdb_dg'. Error is 16047

    Data Guard搭建完毕之后,执行开启归档路径2,结果发现不同步, SQL> alter system set log_archive_dest_state_2=enable; 查看错误日志 ...

  10. 如何配置一个绿色化的 Qt for Windows 开发环境(有.bat脚本,亲测好用) good

    安装 QtCreator for Windows 其实是很简单的,不过,我一向讨厌什么软件都得弄个安装程序,我希望我所安装的这个 Qt 可以是绿色的.便携的,如果无法实现,至少让这个 Qt 可以在新系 ...