POJ 2987 Firing(最大权闭合图)
【题目链接】 http://poj.org/problem?id=2987
【题目大意】
为了使得公司效率最高,因此需要进行裁员,
裁去不同的人员有不同的效率提升效果,当然也有可能是负的效果,
如果裁去一个上级,那么他所管辖的下级需要全部裁掉,问最大效率提升
同时求出最小裁员
【题解】
我们从上司向所有的下属连线会发现裁去的部分恰是一个最大权闭合图
所以按照最大权闭合图建图求最小割,残余网络就是裁员数量。
【代码】
#include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; const int INF=0x3f3f3f3f; const int MAX_V=5010; typedef long long LL; struct edge{int to;LL cap;int rev;}; vector<edge> G[MAX_V]; int V,level[MAX_V],iter[MAX_V]; void add_edge(int from,int to,int cap){ G[from].push_back((edge){to,cap,G[to].size()}); G[to].push_back((edge){from,0,G[from].size()-1}); } void bfs(int s){ memset(level,-1,sizeof(level)); queue<int> que; level[s]=0; que.push(s); while(!que.empty()){ int v=que.front(); que.pop(); for(int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[e.to]<0){ level[e.to]=level[v]+1; que.push(e.to); } } } } LL dfs(int v,int t,LL f){ if(v==t)return f; for(int &i=iter[v];i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[v]<level[e.to]){ LL d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } }return 0; } LL max_flow(int s,int t){ LL flow=0; for(;;){ bfs(s); if(level[t]<0)return flow; memset(iter,0,sizeof(iter)); LL f; while((f=dfs(s,t,INF))>0){ flow+=f; } } } const int MAX_N=5000; const int MAX_M=60000; int N,M,w[MAX_N],a[MAX_M],b[MAX_M]; LL max_weight_closure(int s,int t){ LL W=0; V=t; for(int i=0;i<=V;i++)G[i].clear(); for(int i=0;i<N;i++){ if(w[i]>0)W+=w[i],add_edge(s,i,w[i]); if(w[i]<0)add_edge(i,t,-w[i]); } for(int i=0;i<M;i++){ add_edge(a[i]-1,b[i]-1,INF); } return W-max_flow(s,t); } int leftv,vis[MAX_V]; void cal_res_net(int v){ ++leftv; vis[v]=1; for(int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&!vis[e.to])cal_res_net(e.to); } } void init(){ for(int i=0;i<N;i++)scanf("%d",&w[i]); for(int i=0;i<M;i++)scanf("%d%d",&a[i],&b[i]); } void solve(){ int s=N,t=N+1; LL max_profit=max_weight_closure(s,t); memset(vis,0,sizeof(vis)); leftv=0; cal_res_net(s); printf("%d %lld\n",--leftv,max_profit); } int main(){ while(~scanf("%d%d",&N,&M)){ init(); solve(); }return 0; }
愿你出走半生,归来仍是少年