POJ 2987 Firing (最大权闭合子图)

题意

公司需要裁员。有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;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/81290625