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

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

 

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

 

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

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

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

 

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 }

 

 

你可能感兴趣的:(poj)