poj 2987 Firing 最大权闭合子图

Firing
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 8952   Accepted: 2690

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 ≤ in). The remaining m lines each contain two integers i and j (1 ≤ i, jn) 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.
 
最大权闭合图裸题。
 
最大权闭合图 参考 胡伯涛 算法合集之《最小割模型在信息学竞赛中的应用》
 
闭合图(closure):是有向图点一个点集,且
该点集的所有出边都还指向该点集。即闭合图点任意点点任意后继也一定在闭合图中。
最大权闭合图(maximum weight closure):是一个点权之和最大点闭合图。
闭合图点性质恰好反映来事件间点必要条件的关系。
 
闭合图问题建图方法:
在原图点集的基础上增加源s和汇t,对于原图中点每条边(u,v),在图中连接u,v点,容量为正无穷。
对于权值为正的点。连接源s和该点,容量为该点的权值。
对于权值为负点点。连接汇t和该点。容量为该点的权值。
最大权值 = 所有正权值之和 - 最小割
 
hdu 3061 Battle http://acm.hdu.edu.cn/showproblem.php?pid=3061 和这题一样
 
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cmath>
  5 #include <string>
  6 #include <queue>
  7 #include <vector>
  8 using namespace std;
  9 #define maxn 5010
 10 const int inf = 0x3f3f3f3f;
 11 struct Edge
 12 {
 13     int from, to, cap, flow;
 14     Edge(int f, int t, int c, int fl)
 15     {
 16         from = f; to = t; cap = c; flow = fl;
 17     }
 18 };
 19 vector <Edge> edges;
 20 vector <int> G[maxn];
 21 int vis[maxn], d[maxn], cur[maxn];
 22 int s, t, n, m;
 23 long long min(long long a, long long b)
 24 {
 25     return a<b?a:b;
 26 }
 27 void AddEdge(int from, int to, int cap)
 28 {
 29     edges.push_back(Edge(from, to, cap, 0));
 30     edges.push_back(Edge(to, from, 0, 0));
 31     m = edges.size();
 32     G[from].push_back(m-2);
 33     G[to].push_back(m-1);
 34 }
 35 bool bfs()
 36 {
 37     memset(vis, 0, sizeof(vis));
 38     d[s] = 0;
 39     vis[s] = 1;
 40     queue <int> q;
 41     q.push(s);
 42     while(!q.empty())
 43     {
 44         int u = q.front(); q.pop();
 45         for(int i = 0; i < G[u].size(); i++)
 46         {
 47             Edge &e = edges[G[u][i]];
 48             if(!vis[e.to] && e.cap > e.flow)
 49             {
 50                 vis[e.to] = 1;
 51                 d[e.to] = d[u]+1;
 52                 q.push(e.to);
 53             }
 54         }
 55     }
 56     return vis[t];
 57 }
 58 long long dfs(int x, long long a)
 59 {
 60     if(x == t || a == 0) return a;
 61     long long flow = 0, f;
 62     for(int &i = cur[x]; i < G[x].size(); i++)
 63     {
 64         Edge &e = edges[G[x][i]];
 65         if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
 66         {
 67             e.flow += f;
 68             edges[G[x][i]^1].flow -= f;
 69             flow += f;
 70             a -= f;
 71             if(a == 0) break;
 72         }
 73     }
 74     return flow;
 75 }
 76 long long Maxflow()
 77 {
 78     long long flow = 0;
 79     while(bfs())
 80     {
 81         memset(cur, 0, sizeof(cur));
 82         flow += dfs(s, inf);
 83     }
 84     return flow;
 85 }
 86 int N, M;
 87 int main()
 88 {
 89     while(~scanf("%d%d",  &N, &M))
 90     {
 91         edges.clear();
 92         for(int i = 0; i <= N+1; i++) G[i].clear();
 93         s = 0; t = N+1;
 94         long long sum = 0;
 95         for(int i = 1; i <= N; i++)
 96         {
 97             long long  temp; scanf("%lld", &temp);
 98             if(temp > 0) {AddEdge(s, i, temp); sum += temp;}
 99             else if(temp < 0) AddEdge(i, t, -temp);
100         }
101         for(int i = 1; i <= M; i++)
102         {
103             int a, b; scanf("%d%d", &a, &b);
104             AddEdge(a, b, inf);
105         }
106         sum -= Maxflow();
107         int ans = 0;
108         for(int i = 1; i <= N; i++)
109         {
110             if(vis[i]) ans++;
111         }
112         printf("%d %lld\n", ans, sum);
113     }
114     return 0;
115 }

 

 
 
 
posted @ 2015-08-03 16:47  下周LGD该赢了吧  阅读(230)  评论(0编辑  收藏  举报