poj 2987 最大权闭合图


Language:
Default

Firing

Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 8744   Accepted: 2631

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 individuallybi (|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.

很基础的最大权闭合图

  1 #include<iostream>
  2 #include<queue>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<climits>
  6 #define MAXE 65100*2
  7 #define MAXP 5100
  8 #define Max(a,b) a>b?a:b
  9 #define Min(a,b) a<b?a:b
 10 using namespace std;
 11 struct Edge
 12 {
 13     long long int s,t,next;
 14     long long f;
 15 } edge[MAXE];
 16 long long int head[MAXP];
 17 long long int cur[MAXP];
 18 long long int pre[MAXP];
 19 long long int stack[MAXE];
 20 long long int dep[MAXP];
 21 long long int ent;
 22 long long int n,m,s,t,cot;
 23 void add(long long int start,long long int last,long long int f)
 24 {
 25     edge[ent].s=start;
 26     edge[ent].t=last;
 27     edge[ent].f=f;
 28     edge[ent].next=head[start];
 29     head[start]=ent++;
 30     edge[ent].s=last;
 31     edge[ent].t=start;
 32     edge[ent].f=0;
 33     edge[ent].next=head[last];
 34     head[last]=ent++;
 35 }
 36 bool bfs(long long int S,long long int T)
 37 {
 38     memset(pre,-1,sizeof(pre));
 39     pre[S]=0;
 40     queue<long long int>q;
 41     q.push(S);
 42     while(!q.empty())
 43     {
 44         long long int temp=q.front();
 45         q.pop();
 46         for(long long int i=head[temp]; i!=-1; i=edge[i].next)
 47         {
 48             long long int temp2=edge[i].t;
 49             if(pre[temp2]==-1&&edge[i].f)
 50             {
 51                 pre[temp2]=pre[temp]+1;
 52                 q.push(temp2);
 53             }
 54         }
 55     }
 56     return pre[T]!=-1;
 57 }
 58 long long int dinic(long long int start,long long int last)
 59 {
 60     long long int flow=0,now;
 61     while(bfs(start,last))
 62     {
 63         long long int top=0;
 64         memcpy(cur,head,sizeof(head));
 65         long long int u=start;
 66         while(1)
 67         {
 68             if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流
 69             {
 70                 long long int minn=INT_MAX;
 71                 for(long long int i=0; i<top; i++)
 72                 {
 73                     if(minn>edge[stack[i]].f)
 74                     {
 75                         minn=edge[stack[i]].f;
 76                         now=i;
 77                     }
 78                 }
 79                 flow+=minn;
 80                 for(long long int i=0; i<top; i++)
 81                 {
 82                     edge[stack[i]].f-=minn;
 83                     edge[stack[i]^1].f+=minn;
 84                 }
 85                 top=now;
 86                 u=edge[stack[top]].s;
 87             }
 88             for(long long int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边
 89                 if(edge[i].f&&pre[edge[i].t]==pre[u]+1)
 90                     break;
 91             if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯
 92             {
 93                 if(top==0)break;
 94                 pre[u]=-1;
 95                 u=edge[stack[--top]].s;
 96             }
 97             else//如果找到了继续运行
 98             {
 99                 stack[top++]=cur[u];
100                 u=edge[cur[u]].t;
101             }
102         }
103     }
104     return flow;
105 }
106 void dfs(long long int u)
107 {
108     cot++;
109     dep[u]=1;
110     for(long long int i=head[u];i!=-1;i=edge[i].next)
111     {
112         long long int v=edge[i].t;
113         if(!dep[v]&&edge[i].f>0)
114         {
115             dfs(v);
116         }
117     }
118 }
119 int main()
120 {
121     while(~scanf("%lld%lld",&n,&m))
122     {
123         s=0;
124         t=n+1;
125         ent=0;
126         long long int cost,u,v;
127         long long int ans=0;
128         memset(head,-1,sizeof(head));
129         for(int i=1; i<=n; i++)
130         {
131             scanf("%lld",&cost);
132             if(cost>0)
133             {
134                 add(s,i,cost);
135                 ans+=cost;
136             }
137             else add(i,t,-cost);
138         }
139         for(int i=1; i<=m; i++)
140         {
141             scanf("%lld%lld",&u,&v);
142             add(u,v,INT_MAX);
143         }
144         memset(dep,0,sizeof(dep));
145         long long int flow=dinic(s,t);
146         cot=0;
147         dfs(s);
148         printf("%lld ",cot-1);
149         printf("%lld\n",ans-flow);
150     }
151     return 0;
152 }

时间: 2024-11-03 22:16:25

poj 2987 最大权闭合图的相关文章

hdu 2987最大权闭合图模板类型题

/* 最大权闭合图模板类型的题,考验对知识概念的理解. 题意:现在要辞退一部分员工,辞退每一个员工可以的到一部分利益(可以是负的),并且辞退员工,必须辞退他的下属,求最大利益和辞退的最小人数. 最大权闭合图模板类型. 求出最大权后沿着源点s,dfs到的点就为最小的人数. 证明/* 转载:利用一个经典的trick:多关键字 > 建图前,对所有b[i],执行变换b[i]=b[i]*10000-1,然后,会惊异地发现, > 此时最大流所对应的方案就是满足辞退最少人数的了. > 为什么?显然,变

poj Firing(最大权闭合图)

Firing 题目: 要解雇一些人,而解雇的这些人如果人跟他有上下级的关系,则跟他有关系的人也要一起解雇.每个人都会创造一定的价值,要求你求出在最大的获利下,解雇的人最小. 算法分析: 在这之前要知道一个定理: 最小割 = 最大流 一道最大权闭合图的裸题,而这又可以转换成最小割来求解.证明可以看2007年胡伯涛的论文则可以直接套出模板,没看过的最好去看一下,那里解释的清楚.这里我给出他的原文的一些构造方法. 增加源s汇t 源s连接原图的正权点,容量为相应点权 原图的负权点连接汇t,容量为相应点权

poj - 2987 - Firing(最大权闭合图)

题意:n(0 < n ≤ 5000)个人,m(0 ≤ m ≤ 60000)个上下级关系,炒一个人可以获得收益或者损失bi (|bi| ≤ 10 ^ 7, 1 ≤ i ≤ n),炒一个人会把他的所有下级一起炒掉,问怎样炒人使收益最大,输出最大收益和最少炒人的数量. 题目链接:http://poj.org/problem?id=2987 -->>炒一个人会把他的所有下级一起炒掉,这时存在依赖关系,对应图论中的闭合图..最大收益对应最大权和..于是,最大权闭合图上场.. 最少炒人数?获得最大收

POJ 2987 Firing (最大权闭合图,最小割)

http://poj.org/problem?id=2987 Firing Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7865   Accepted: 2377 Description You've finally got mad at "the world's most stupid" employees of yours and decided to do some firings. You're n

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

http://poj.org/problem?id=2987 https://blog.csdn.net/u014686462/article/details/48533253 给一个闭合图,要求输出其最大权闭合图的权值和需要选的最少点数,最大权闭合图定义和网络流连边方式见博客. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include&

POJ 2987 Firing 最大权闭合图

点击打开链接 Firing Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7976   Accepted: 2409 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 giv

POJ_2987_Firing(最大流+最大权闭合图)

描述 http://poj.org/problem?id=2987 要炒员工鱿鱼,炒了一个人,他的下属一定被炒.给出每个人被炒后公司的收益(负值表示亏损),问怎样炒公司收益最大,以及这种方法炒了几个人.(先输出人数) 分析 求最大收益是用最大权闭合图.要炒一个人,他的下属也要被炒,那么边由上司连向下属,求最大权闭合图即可. 求炒了几个人实际是就是求先前求出来的那个最大权闭合图中点的个数.最大权闭合图对应的是最小割,而最小割中的边都是满流的,所以从源点出发无法到达闭合图的补集(即T),并且由于是闭

HDU 3061:Battle(最大权闭合图)

http://acm.hdu.edu.cn/showproblem.php?pid=3061 题意:中文题意. 思路:和上一题神似啊,比上一题还简单,重新看了遍论文让我对这个理解更加深了. 闭合图:如果某个点在图中的话,那么这个点的后继点全部都要在图中. 对应至题目,这里的必须攻占b以后才能攻占a,那么是a依赖于b.如果a在图中的话,那么b必定在图中(因为a是依赖于b的),所以是a连向b(而不是b连向a). 这里总结一下做最大权闭合图的套路:把权值为正的点与超级源点S相连,容量为该权值,把权值为

HDU5772 String problem 最大权闭合图+巧妙建图

题意:自己看吧(不是很好说) 分析: 网络流:最大权闭合子图. 思路如下: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点