博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ2987:Firing——题解
阅读量:6623 次
发布时间:2019-06-25

本文共 2209 字,大约阅读时间需要 7 分钟。

题目大意:

炒掉一个人能够获得b收益(b可以<0),但是炒掉一个人必须得炒掉他的下属(然后继续递归)。

求最大收益和此时最小裁员。

——————————————————————————————

我们需要用到最大权闭合图的知识。

为什么呢?我们把u是v的上司变成u—>v,那么我们要求的就是当前图的最大权闭合图。

那么按照最大权闭合图的知识建立图跑最大流即可。

如何求最大权闭合图:

先在原图中添加s(源点)和t(汇点),原图中的边权全部设为INF,权值为正的点与s连边,权值为点的权值,为负则与t连边,权值为负的点的权值。

答案为原图中权值为正的点的和 - 最小割(最大流)

(以下证明不一定严谨)

然后考虑多少人,我们发现原来减掉的最小割就可以表示成我们没有裁的人的权值,那么没有裁的人必然流满了。

所以我们裁掉的人就是我们最小割没有流满的人,dfs一下即可。

//不开long long见祖宗,十年OI一场空。

#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;const int INF=2147483640;const int maxn=5010;inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X;}int S,T;struct node{ int nxt; int to; ll w;}edge[60000*2+maxn*2+1];int head[maxn],cnt=-1;void add(int u,int v,int w){ cnt++; edge[cnt].to=v; edge[cnt].w=w; edge[cnt].nxt=head[u]; head[u]=cnt; return;}int lev[maxn],cur[maxn];bool bfs(int m){ int dui[m],r=0; for(int i=1;i<=m;i++){ lev[i]=-1; cur[i]=head[i]; } dui[0]=S,lev[S]=0; int u,v; for(int l=0;l<=r;l++){ u=dui[l]; for(int e=head[u];e!=-1;e=edge[e].nxt){ v=edge[e].to; if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1; r++; dui[r]=v; if(v==T)return 1; } } } return 0; }ll dinic(int u,int flow,int m){ if(u==m)return flow; ll res=0,delta; for(int &e=cur[u];e!=-1;e=edge[e].nxt){ int v=edge[e].to; if(edge[e].w>0&&lev[u]
0){ edge[e].w-=delta; edge[e^1].w+=delta; res+=delta; if(res==flow)break; } } } if(res!=flow)lev[u]=-1; return res;}bool vis[maxn];int dfs(int u){ int ans=1; vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i].w>0&&!vis[v]){ ans+=dfs(v); } } return ans;}int main(){ memset(head,-1,sizeof(head)); int n=read(); int m=read(); S=n+1;T=n+2; ll sum=0; for(int i=1;i<=n;i++){ ll b=read(); if(b>0){ sum+=b; add(S,i,b); add(i,S,0); }else{ add(i,T,-b); add(T,i,0); } } for(int i=1;i<=m;i++){ int a=read(); int b=read(); add(a,b,INF); add(b,a,0); } ll ans=0; while(bfs(T))ans+=dinic(S,INF,T); printf("%d %lld\n",dfs(S)-1,sum-ans); return 0;}

 

转载于:https://www.cnblogs.com/luyouqi233/p/7942879.html

你可能感兴趣的文章
WEB前端资源代码:学习篇
查看>>
Nginx安装及配置详解【转】
查看>>
vue2.0 :style :class样式设置
查看>>
测不准原理主要指向微观
查看>>
linux 守护进程 daemon
查看>>
C#获取当前程序运行路径的方法集合
查看>>
使用Bootstrap 3开发响应式网站实践04,使用Panels展示内容
查看>>
ajax核心代码(转载)
查看>>
项目正式启动
查看>>
python中unicode、utf8、gbk等编码问题
查看>>
赵振平:项目成败取决于数据库架构设计
查看>>
WPF专业编程指南
查看>>
互动网计算机频道图书7日销售排行(06.17-06.23)
查看>>
《Google App Engine编程:英文版》china-pub预定中
查看>>
指针引用的用法
查看>>
UNC path
查看>>
HTML5与Flash比较
查看>>
SSL系统遭入侵发布虚假密钥 微软谷歌受影响
查看>>
微软ASP.NET站点部署指南(8):部署Code-Only更新
查看>>
[苏飞开发助手V1.0测试版]官方教程与升级报告
查看>>