題目鏈接:http://poj.org/problem?id=2987
題目大意:一個公司有n個員工(里面包括董事長,經理,普通員工等等),現在遇見了金融危機,公司要開始裁員了,每個人對公司的價值不一樣(可能為正可能為負),當你裁員一個員工時,這個員工他手下的員工必須一起裁掉,問你如何裁員能使公司得到的利益最大,而這種裁員方法必須得裁掉多少個員工。
建圖模型:最大權閉合子圖指選擇u,則u以下關系的都要選,一定要選到底,不能跳過u選它以下的。增設一個超級源點和一個超級匯點,(1->n)的點中,當點權為正時,從源點向該點連一條權值為點權大小的邊,當點權為負時,從該點連一條權值大小為它的絕對值的邊連向匯點。這種問題一般都是對於(u,v),如果選擇u必須選擇v,對(u,v)連一條容量為oo的邊。
裁員數等於靠近源點最小割一邊的點數,最大利益=所有點正權值之和-最小割。

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 }