题干:

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 ≤ ij ≤ 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.

Sample Input

5 5
8
-9
-20
12
-10
1 2
2 5
1 4
3 4
4 5

Sample Output

2 2

Hint

As of the situation described by the sample input, firing employees 4 and 5 will produce a net profit of 2, which is maximum.

题目大意:

公司解雇员工,每个员工有一个权值,可正可负可为零(为正代表解雇员工可以获得的利润,为负代表获得的利润为负)。然后给出一些员工上下级的关系,如果解雇一个员工(比如经理主管之类的),那么他手下的所有员工都会被解雇。注意一点:公司有很多部门,每个人可能不只效力于一个部门,所以有可能在这个部门A是B的上司,在另一个部门内B是A的上司。(其实就是代表图中可能有环)问对公司获利最大的解雇计划以及最少的解雇员工人数。

解题报告:

看起来就是个最大权闭合图。但是不知道怎么证明这样得到的就是最少的解雇人数了、、

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 5e5 + 5;
int n,m;
int tot;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct Edge {int to,ne;ll w;
} e[MAX];
int head[MAX];
int st,ed;
ll a[MAX],dis[MAX];
int q[MAX];//一共多少个点跑bfs,dis数组和q数组就开多大。
void add(int u,int v,ll w) {e[++tot].to=v;e[tot].w=w;e[tot].ne=head[u];head[u]=tot;
}
bool bfs(int st,int ed) {memset(dis,-1,sizeof(dis));int front=0,tail=0;q[tail++]=st;dis[st]=0;while(front<tail) {int cur = q[front];if(cur == ed) return 1;front++;for(int i = head[cur]; i!=-1; i = e[i].ne) {if(e[i].w&&dis[e[i].to]<0) {q[tail++]=e[i].to;dis[e[i].to]=dis[cur]+1;}}}if(dis[ed]==-1) return 0;return 1;
}
ll dfs(int cur,ll limit) {//limit为源点到这个点的路径上的最小边权 if(limit==0||cur==ed) return limit;ll w,flow=0;for(int i = head[cur]; i!=-1; i = e[i].ne) {       if(e[i].w&&dis[e[i].to]==dis[cur]+1) {w=dfs(e[i].to,min(limit,e[i].w));e[i].w-=w;e[i^1].w+=w;flow+=w;limit-=w;if(limit==0) break;}}if(!flow) dis[cur]=-1;return flow;
}
ll dinic() {ll ans = 0;while(bfs(st,ed)) ans+=dfs(st,INF);//0x7fffffff可能就不对了? return ans;
}
int ans2;
bool vis[MAX];
void dfs2(int cur) {if(cur == ed) return;vis[cur] = 1;ans2++;for(int i = head[cur]; ~i; i = e[i].ne) {int v = e[i].to;if(e[i].w == 0 || vis[v]) continue;dfs2(v);}
}
int main()
{cin>>n>>m;st=0;ed=n+1;tot=1;ll sum = 0;for(int i = 0; i<=n+1; i++) head[i] = -1;for(int i = 1; i<=n; i++) {scanf("%lld",a+i);if(a[i] > 0) sum += a[i],add(st,i,a[i]),add(i,st,0);if(a[i] < 0) add(i,ed,-a[i]),add(ed,i,0);}for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b,INF);add(b,a,0);}ll ans = sum - dinic();dfs2(st);printf("%d %lld\n",ans2-1,ans);return 0;
}

玄学方法:

这题的特殊之处就是要输出最少辞退员工数。
怎么办呢?

利用一个经典的trick:多关键字
建图前,对所有b[i],执行变换b[i]=b[i]*10000-1,然后,会惊异地发现,
此时最大流所对应的方案就是满足辞退最少人数的了。
为什么?显然,变换后的流量r2除以10000后再取整就等于原来的流量,但是
r2的后四位却蕴含了辞退人数的信息:每多辞退一个人,流量就会少1。

剩下的就是如何根据一个网络流输出方案。
我的做法:从源点开始沿着残余网络dfs(只走没有满载的边),
能dfs到的点对应的人就是需要辞退的。

int main()
{cin>>n>>m;st=0;ed=n+1;tot=1;ll sum = 0;for(int i = 0; i<=n+1; i++) head[i] = -1;for(int i = 1; i<=n; i++) {scanf("%lld",a+i);a[i] = a[i]*10000-1;if(a[i] > 0) sum += a[i],add(st,i,a[i]),add(i,st,0);if(a[i] < 0) add(i,ed,-a[i]),add(ed,i,0);}for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b,INF);add(b,a,0);}ll ans = sum - dinic();dfs2(st);printf("%d %lld\n",ans2-1,(ans+9999)/10000);return 0;
}

或者不用dfs2:

int main()
{cin>>n>>m;st=0;ed=n+1;tot=1;ll sum = 0;for(int i = 0; i<=n+1; i++) head[i] = -1;for(int i = 1; i<=n; i++) {scanf("%lld",a+i);a[i] = a[i]*10000 - 1;if(a[i] > 0) sum += a[i],add(st,i,a[i]),add(i,st,0);if(a[i] < 0) add(i,ed,-a[i]),add(ed,i,0);}for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b,INF);add(b,a,0);}ll ans = sum - dinic();
//  ans2 = -(ans % 10000 - 10000) % 10000 ;//这两个用哪个都可以ans2 = (10000 - ans%10000)%10000 ;//别忘最后要%10000!!不然ans==10000的时候就WA了ans = (ans+ans2)/10000;
//  dfs2(st);printf("%d %lld\n",ans2,ans);return 0;
}

【POJ - 2987】Firing(最大权闭合图,网络流最小割,输出方案最小,放大权值法tricks)相关推荐

  1. 51nod1551-集合交易【hall定理,最大权闭合图,网络流】

    正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1551 题目大意 nnn个集合,nnn个物品,每个集合有一些物品,一个价钱 ...

  2. 51nod1325-两棵树的问题【最大权闭合图,网络流】

    正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1325 题目大意 两棵树.要求选出一组权值和最大的点使得这两个点集在两棵树 ...

  3. 最大权闭合 图 讲解

    详见  国家集训队 论文 2007  胡伯涛 <最小割模型在信息学竞赛中的应用> 首先说几个我看时疑惑的问题   1:为什么 割里面的点集就是闭合 图 ? 答:由于 我们见图时,将原图的 ...

  4. 二、太空飞行计划问题 [最大权闭合图]

    太空飞行计划问题 问题描述: W教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进行这些实验需 ...

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

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

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

    http://poj.org/problem?id=2987 题意: 公司要由于经济 问题 要 裁员工,已知,要采取某个 员工,那么 他的下属也将被 裁去,给出  裁出 n  个员公的 所获的利益 ( ...

  7. 【POJ - 2987 】Firing 【最大权闭合图有唯一的 势 】

    You've finally got mad at "the world's most stupid" employees of yours and decided to do s ...

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

    题目链接:点击查看 题目大意:某公司想要裁员,裁员的标准是如果某人被裁,那么其下属也会被裁,依此类推,每一个人都有一个贡献度,问怎样裁员才能使得最后的贡献度最大并且裁掉人数最少 题目分析:最大权闭合图 ...

  9. YBTOJ:矛盾指数(网络流-最大权闭合图)

    文章目录 题目描述 解析 代码 网络流要大胆建图 题目描述 公司内部共nnn个员工,员工之间可能有矛盾.若员工uuu和员工vvv有矛盾,用边(u,v)(u,v)(u,v)表示,共mmm个矛盾. 现在公 ...

最新文章

  1. iis6.0怎么搭php,IIS6.0平台下PHP最佳配置方法
  2. python操作手机app_【Python】[技术博客] 一些使用Python编写获取手机App日志的操作...
  3. wince 自带的web server
  4. 互联网日报 | 6月12日 星期六 | BOSS直聘正式登陆纳斯达克;腾讯回应“试点强制6点下班”;数据安全法9月1日起实施...
  5. js字符串与数字比较大小
  6. fiddler限速_fiddler限制网速
  7. 视频解析工具youtube-dl
  8. 全国省市区三级JSON 包括地区编码
  9. photoshop切片的使用
  10. FC光钎通道交换机,同行性价比超高
  11. A-Weighting(A计权网络)
  12. JavaEE中的网络基础知识和网络通信基础
  13. 相机XD卡格式化后,照片恢复
  14. 一牛网:最新6月手机综合性能评测
  15. 响应状态码1xx , 2xx,3xx , 4xx , 5xx
  16. Dell Inspiron 5520 笔记本盲刷BIOS
  17. 财神来了 | 存量资金博弈下,是谁在吸血
  18. STM32_基础篇(1)学习资料准备
  19. 干货分享~做到这几点可以高效地Revit建模!
  20. 外地户籍应届毕业生落户上海申请及办理流程(2017更新)

热门文章

  1. hdu 4324 Triangle LOVE
  2. python第三方库全部_自动更新Python所有第三方库
  3. excel亮灯怎么设置_Excel表格技巧—怎么给表格设置密码
  4. vue 生命周期_Vue生命周期小白看了都会的
  5. centos安装无线网卡驱动_CentOS下显卡驱动安装的相关思考
  6. 上海大学c语言作业答案,《上海大学C语言选择题》.doc
  7. java如何保证类不被回收_垃圾回收机制保证了Java程序不会出现内存溢出。( )
  8. ff14拆区后哪个服务器人最多,FF14拆区可以转服吗 拆区期间转服教程
  9. python选取tensor某一维_Pytorch的Tensor操作(1)
  10. java 观察者模式_图解Java设计模式之观察者模式