题意
公司需要裁员。有n个员工作为被裁获选人,裁掉第i个人会获得价值w[i].但是裁掉x之前,需要先裁掉x的直属上司y。求裁掉几个人获得价值最大,最大价值是多少。
解题
根据题意,x与y的依赖关系,所裁掉的人一定是一个闭合子图。即图中出边所指向的点仍然在图中。
所以,这是一个最大权闭合子图问题。
建图跑一遍最大流求出最大权。
然后从源点S进行dfs,dfs能进行的次数就是闭合子图中点的大小。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
using namespace std;
long long S,T;//源点和汇点
const long long maxe=5e5+1000;
const long long maxv=5e3+7;
struct edge
{
long long to,w,next;
}e[maxe<<1];
long long head[maxv<<1],depth[maxv],cnt;
void init()
{
memset(head,-1,sizeof(head));
cnt=-1;
}
void add_edge(long long u,long long v,long long w)
{
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
void _add(long long u,long long v,long long w)
{
add_edge(u,v,w);
add_edge(v,u,0);
}
bool bfs()
{
queue<long long> q;
while(!q.empty()) q.pop();
memset(depth,0,sizeof(depth));
depth[S]=1;
q.push(S);
while(!q.empty())
{
long long u=q.front();q.pop();
for(long long i=head[u];i!=-1;i=e[i].next)
{
if(!depth[e[i].to] && e[i].w>0)
{
depth[e[i].to]=depth[u]+1;
q.push(e[i].to);
}
}
}
if(!depth[T]) return false;
return true;
}
long long dfs(long long u,long long flow)
{
if(u==T) return flow;
long long ret=0;
for(long long i=head[u];i!=-1 && flow;i=e[i].next)
{
if(depth[u]+1==depth[e[i].to] && e[i].w!=0)
{
long long tmp=dfs(e[i].to,min(e[i].w,flow));
if(tmp>0)
{
flow-=tmp;
ret+=tmp;
e[i].w-=tmp;
e[i^1].w+=tmp;
}
}
}
return ret;
}
long long Dinic()
{
long long ans=0;
while(bfs())
{
ans+=dfs(S,INF);
}
return ans;
}
const int maxm=6e4+7;
bool vis[maxv];
struct node
{
int u,v;
}a[maxm];
int tm=0;
void DFS(int u)//.
{
vis[u]=true;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(vis[v] || e[i].w<=0) continue;
tm++;
DFS(v);
}
}
int main()
{
long long n,m;
while(~scanf("%lld%lld",&n,&m))
{
init();
tm=0;
S=0,T=n+1;
long long sum=0;
for(long long i=1;i<=n;i++)
{
long long c;
scanf("%lld",&c);
if(c>0) _add(S,i,c),sum+=c;
else _add(i,T,-c);
}
for(long long i=1;i<=m;i++)
{
long long u,v;
scanf("%lld%lld",&u,&v);
a[i].u=u,a[i].v=v;
_add(u,v,INF);
}
long long ans=Dinic();
memset(vis,false,sizeof(vis));
DFS(S);
printf("%d %lld\n",tm,sum-ans);
}
return 0;
}