【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 }