【POJ 2987 Firing】 最大权闭合子图

题目链接:http://poj.org/problem?id=2987

 

题目大意:一个公司有n个员工(里面包括董事长,经理,普通员工等等),现在遇见了金融危机,公司要开始裁员了,每个人对公司的价值不一样(可能为正可能为负),当你裁员一个员工时,这个员工他手下的员工必须一起裁掉,问你如何裁员能使公司得到的利益最大,而这种裁员方法必须得裁掉多少个员工。

 

建图模型:最大权闭合子图指选择u,则u以下关系的都要选,一定要选到底,不能跳过u选它以下的。增设一个超级源点和一个超级汇点,(1->n)的点中,当点权为正时,从源点向该点连一条权值为点权大小的边,当点权为负时,从该点连一条权值大小为它的绝对值的边连向汇点。这种问题一般都是对于(u,v),如果选择u必须选择v,对(u,v)连一条容量为oo的边。

裁员数等于靠近源点最小割一边的点数,最大利益=所有点正权值之和-最小割。

 

View Code
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int mn=5555;
  9 const int mm=222222;
 10 const int oo=1e9;
 11 int node, st, sd, edge;
 12 int ver[mm], flow[mm], next[mm];
 13 int head[mn], work[mn], dis[mn], q[mn], visit[mn];
 14 
 15 inline void init(int _node, int _st, int _sd)
 16 {
 17     node=_node, st=_st, sd=_sd;
 18     for(int i=0; i<node; i++)
 19         head[i]=-1;
 20     edge=0;
 21 }
 22 
 23 void addedge(int u, int v, int c1, int c2)
 24 {
 25     ver[edge]=v, flow[edge]=c1, next[edge]=head[u],head[u]=edge++;
 26     ver[edge]=u, flow[edge]=c2, next[edge]=head[v],head[v]=edge++;
 27 }
 28 bool Dinic_bfs()
 29 {
 30     int i,u,v,l,r=0;
 31     for(i=0; i<node; ++i)dis[i]=-1;
 32     dis[q[r++]=st]=0;
 33     for(l=0; l<r; ++l)
 34         for(i=head[u=q[l]]; i>=0; i=next[i])
 35             if(flow[i]&&dis[v=ver[i]]<0)
 36             {
 37                 dis[q[r++]=v]=dis[u]+1;
 38                 if(v==sd)return 1;
 39             }
 40     return 0;
 41 }
 42 long long Dinic_dfs(int u, int exp)
 43 {
 44     if(u==sd) return exp;
 45     for(int &i=work[u]; i>=0; i=next[i])
 46     {
 47         int v=ver[i], tp;
 48         if(flow[i]&&dis[v]==dis[u]+1&&(tp=Dinic_dfs(v,min(flow[i],exp)))>0)
 49         {
 50             flow[i]-=tp;
 51             flow[i^1]+=tp;
 52             return tp;
 53         }
 54     }
 55     return 0;
 56 }
 57 long long Dinic_flow()
 58 {
 59     int i,delta;
 60     long long ret=0;
 61     while(Dinic_bfs())
 62     {
 63         for(i=0; i<node; ++i)work[i]=head[i];
 64         while(delta=Dinic_dfs(st,oo))ret+=delta;
 65     }
 66     return ret;
 67 }
 68 
 69 void DFS(int u)
 70 {
 71     visit[u]=1;
 72     for(int i=head[u], v; i>=0; i=next[i])
 73         if(flow[i]>0&&!visit[v=ver[i]]) DFS(v);
 74 }
 75 
 76 int main()
 77 {
 78     int n, m, w, u, v;
 79     while(~scanf("%d%d",&n,&m))
 80     {
 81         init(n+2,0,n+1);
 82         long long sum=0;
 83         for(int i=1; i<=n; i++)
 84         {
 85             scanf("%d",&w);
 86             if(w>0) sum+=w,addedge(st,i,w,0);
 87             if(w<0)  addedge(i,sd,-w,0);;
 88         }
 89         while(m--)
 90         {
 91             scanf("%d%d",&u,&v);
 92             addedge(u,v,oo,0);
 93         }
 94         long long maxflow=Dinic_flow();
 95         memset(visit,0,sizeof(visit));
 96         DFS(st);
 97         int ans=0;
 98         for(int i=1; i<=n; i++) ans+=visit[i];
 99         printf("%d %I64d\n",ans,sum-maxflow);
100     }
101     return 0;
102 }

 

 

posted @ 2013-04-05 21:34  Mr. Ant  阅读(4047)  评论(0编辑  收藏  举报