POJ2987 Firing

来源:互联网 发布:手机淘宝网购流程图 编辑:程序博客网 时间:2024/05/22 12:48
Firing
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 11037 Accepted: 3335

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 ≤ 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 58-9-2012-101 22 51 43 44 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.

Source

POJ Monthly--2006.08.27, frkstyc



网上题解有点想吐槽...模板写的都太...了,hzw的模板还不错,这题算是道网络流dinic模板题吧,主要是帖模板。

至于建图嘛...其实挺简单的,这题用到的是先炒掉所有员工(收益为正的),然后再减去最小割。

源点S连向所有收益为正的点,流量为收益,收益为负的点连向汇点,流量为-收益。然后上司连向下属,这样源点连上司的边被割掉了就可以割掉下属连汇点的边,而反过来没影响,然后再跑最大流即可。



#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#define ll long long#define N 5000+50using namespace std;int head[N],dis[N],vis[N],cur[N],n,m,num,x,S,T,cnt,u,v;ll sum,ans;const int inf=1e9;struct edge{int from,to,next,cap;}e[200000+2000];inline void add_edge(int u,int v,int c){e[++cnt]=(edge){u,v,head[u],c};head[u]=cnt;e[++cnt]=(edge){v,u,head[v],0};head[v]=cnt;}bool bfs(){queue<int>q;for(int i=0;i<=T;i++) dis[i]=-1;q.push(S);dis[S]=0;while(!q.empty()){int now=q.front();q.pop();for(int i=head[now];i;i=e[i].next)if(e[i].cap && dis[e[i].to]==-1){dis[e[i].to]=dis[now]+1;q.push(e[i].to);}}return dis[T]!=-1;}int dfs(int x,int f){if(x==T) return f;int w,used=0;for(int i=cur[x];i;i=e[i].next)if(dis[e[i].to]==dis[x]+1){w=f-used;w=dfs(e[i].to,min(w,e[i].cap));e[i].cap-=w;e[i ^ 1].cap+=w;if(e[i].cap) cur[x]=i;used+=w;if(used==f) return f;}if(!used) dis[x]=-1;return used;}void dinic(){while(bfs()){for(int i=0;i<=T;i++) cur[i]=head[i];ans+=dfs(0,inf);}}void work(int u){for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(vis[v] || !e[i].cap) continue;vis[v]=1;num++;work(v);}}int main(){scanf("%d%d",&n,&m);cnt=1;S=0;T=n+1;for(int i=1;i<=n;i++){scanf("%d",&x);if(x>0) sum+=x,add_edge(S,i,x);else add_edge(i,T,-x);}while(m--){scanf("%d%d",&u,&v);add_edge(u,v,inf);}dinic();vis[S]=1;num=0;work(S);printf("%d %lld\n",num,sum-ans);return 0;}


原创粉丝点击