题意:
一个公司打算解雇一些员工,已知解雇每个人的收益值(可能为负)。解雇某一个人后,他的下属也将被解雇,求最大收益是多少,在取得最大收益时需要解雇多少人。
题解:
建图不多啰嗦,挺裸的~
求最少的割边数目,可以从源点对残量网络进行一次DFS,每个割都会将源点和汇点隔开,所以从源点DFS下去一定会碰到某个割dfs停止,这时遍历过的点数最少的裁员数目。那种直接找满流边的做法是显然不对的奥~
ps:总是wa盛怒之下,把所有int替换了ac了。。。
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <iostream> 5 6 #define N 100100 7 #define M 3000000 8 #define INF 100000000 9 10 using namespace std; 11 //理解最大权闭合图的最小割的含义 12 __int64 head[N],to[M],next[M],len[M],sum,n,m,cnt,S,T,layer[N],q[M<<2],num,ans; 13 bool vis[N]; 14 15 inline void add(__int64 u,__int64 v,__int64 wp) 16 { 17 to[cnt]=v; len[cnt]=wp; next[cnt]=head[u]; head[u]=cnt++; 18 to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++; 19 } 20 21 void read() 22 { 23 memset(head,-1,sizeof head);cnt=0; 24 S=0,T=n+1;sum=0; 25 for(__int64 i=1,a;i<=n;i++) 26 { 27 scanf("%I64d",&a); 28 if(a>=0) 29 { 30 sum+=a; 31 add(S,i,a); 32 } 33 else add(i,T,-a); 34 } 35 for(__int64 i=1,a,b;i<=m;i++) 36 { 37 scanf("%I64d%I64d",&a,&b); 38 add(a,b,INF); 39 } 40 } 41 42 bool bfs() 43 { 44 memset(layer,-1,sizeof layer); 45 __int64 h=1,t=2,sta; 46 q[1]=S; layer[S]=0; 47 while(h<t) 48 { 49 sta=q[h++]; 50 for(__int64 i=head[sta];~i;i=next[i]) 51 if(len[i]&&layer[to[i]]<0) 52 { 53 layer[to[i]]=layer[sta]+1; 54 q[t++]=to[i]; 55 } 56 } 57 return layer[T]!=-1; 58 } 59 60 __int64 find(__int64 u,__int64 cur_flow) 61 { 62 if(u==T) return cur_flow; 63 __int64 result=0,tmp; 64 for(__int64 i=head[u];~i&&result<cur_flow;i=next[i]) 65 if(len[i]&&layer[to[i]]==layer[u]+1) 66 { 67 tmp=find(to[i],min(cur_flow-result,len[i])); 68 len[i]-=tmp; len[i^1]+=tmp; result+=tmp; 69 } 70 if(!result) layer[u]=-1; 71 return result; 72 } 73 74 void dinic() 75 { 76 ans=0; 77 while(bfs()) ans+=find(S,INF); 78 79 } 80 81 void dfs(__int64 u) 82 { 83 if(u==T) return; 84 vis[u]=true; 85 for(__int64 i=head[u];~i;i=next[i]) 86 if(!vis[to[i]]&&len[i]>0) 87 dfs(to[i]); 88 } 89 90 int main() 91 { 92 while(scanf("%I64d%I64d",&n,&m)!=EOF) 93 { 94 read(); 95 dinic(); 96 num=0; 97 memset(vis,0,sizeof vis); 98 dfs(S); 99 for(__int64 i=1;i<=n;i++) 100 if(vis[i]) num++; 101 printf("%I64d %I64d\n",num,sum-ans); 102 } 103 return 0; 104 }