zoukankan      html  css  js  c++  java
  • POJ2987 Firing 【最大权闭合图】

    POJ2987 Firing


    Description

    You’ve finally got mad at “the world’s most stupid” employees of yours and decided to do some firings. You’re now simply too mad to give response to questions like “Don’t you think it is an even more stupid decision to have signed them?”, yet calm enough to consider the potential profit and loss from firing a good portion of them. While getting rid of an employee will save your wage and bonus expenditure on him, termination of a contract before expiration costs you funds for compensation. If you fire an employee, you also fire all his underlings and the underlings of his underlings and those underlings’ underlings’ underlings… An employee may serve in several departments and his (direct or indirect) underlings in one department may be his boss in another department. Is your firing plan ready now?

    Input

    The input starts with two integers n (0 < n ≤ 5000) and m (0 ≤ m ≤ 60000) on the same line. Next follows n + m lines. The first n lines of these give the net profit/loss from firing the i-th employee individually bi (|bi| ≤ 107, 1 ≤ i ≤ n). The remaining m lines each contain two integers i and j (1 ≤ i, j ≤ n) meaning the i-th employee has the j-th employee as his direct underling.

    Output

    Output two integers separated by a single space: the minimum number of employees to fire to achieve the maximum profit, and the maximum profit.

    Sample Input

    5 5
    8
    -9
    -20
    12
    -10
    1 2
    2 5
    1 4
    3 4
    4 5

    Sample Output

    2 2

    Hint

    As of the situation described by the sample input, firing employees 4 and 5 will produce a net profit of 2, which is maximum.


    题意就是有一些员工,开除一个员工会得到相应的盈利或者亏损
    然后员工之间有一些上司和下属的关系,如果开除一个上司必须要开除他的所有下属
    最大化盈利,输出开除的员工数和盈利数
    一开始不知道这是最大权闭合图,后面看到网上的介绍才了解。
    那么什么是闭合图呢?
    在一个图中,我们选取一些点构成集合,且集合中的点向外连出的弧所指向的终点也在集合中,则我们称这个集合为闭合图
    那么最大权闭合图就是所有闭合图中权值和最大的一个
    了解了概念之后,我们如何对这一类问题进行解决呢?
    我们构造一个流量网络满足以下条件:
    1 存在源点S和汇点T
    2 对于所有权值为正的点,连接一条容量为点权,从S到这个点的边
    3 对于所有权值为负的点,连接一条容量为点权相反数,从这个点到T的边
    4 原图中连接两点的边,在流量网络中用容量为INF的边连接
    在最大权闭合图中,有以下性质
    1 最小割为简单割:割集的每条边都与S或T关联
    2 最小割和S点关联的集合减去S点就是最大权闭合图

    我们根据这两个性质就可以对问题进行求解了
    感觉其实是到板子题


    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LL long long
    #define N 10010
    struct Edge{
        LL u,v,cap,flow;
        Edge(LL xu,LL xv,LL xcap,LL xflow){
            u=xu;v=xv;cap=xcap;flow=xflow;
        }
    };
    struct Dinic{
        LL s,t,vis[N],d[N];
        vector<Edge> E;
        vector<LL> G[N];
        void add(LL u,LL v,LL cap){
            E.push_back(Edge(u,v,cap,0));
            E.push_back(Edge(v,u,0,0));
            LL m=E.size();
            G[u].push_back(m-2);
            G[v].push_back(m-1); 
        }
        bool BFS(){
            memset(vis,0,sizeof(vis));
            memset(d,0,sizeof(d));
            queue<LL> Q;
            Q.push(s);
            vis[s]=1;
            while(!Q.empty()){
                LL u=Q.front();Q.pop(); 
                for(LL i=0;i<G[u].size();i++){
                    Edge &e=E[G[u][i]];
                    if(!vis[e.v]&&e.cap>e.flow){
                        vis[e.v]=1;
                        d[e.v]=d[u]+1;
                        Q.push(e.v);
                    }
                }
            }
            return vis[t];
        }
        LL DFS(LL u,LL a){
            if(u==t||!a)return a;
            LL flow=0;
            for(LL i=0;i<G[u].size();i++){
                Edge &e=E[G[u][i]];
                if(d[e.v]!=d[u]+1)continue;
                LL f=DFS(e.v,min(a,e.cap-e.flow));
                e.flow+=f;
                E[G[u][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(!a)break;
            }
            return flow;
        }
        LL Maxflow(){
            LL flow=0;
            while(BFS())flow+=DFS(s,INF);
            return flow;
        }
        void search(LL u){
            vis[u]=1;
            for(LL i=0;i<G[u].size();i++){
                Edge e=E[G[u][i]];
                if(e.cap-e.flow>0&&!vis[e.v])search(e.v);
            }
        }
    }dinic;
    LL n,m,p,q,sum=0;
    int main(){
        scanf("%lld%lld",&n,&m);
        dinic.s=0;dinic.t=n+1;
        for(LL i=1;i<=n;i++){
            scanf("%lld",&p);
            if(p>0)dinic.add(0,i,p),sum+=p;
            else dinic.add(i,n+1,-p);
        }
        for(LL i=1;i<=m;i++){
            scanf("%lld%lld",&p,&q);
            dinic.add(p,q,INF);
        }
        LL ans1=0,ans2=sum-dinic.Maxflow();
        memset(dinic.vis,0,sizeof(dinic.vis));
        dinic.search(dinic.s);
        for(LL i=1;i<=n;i++)ans1+=dinic.vis[i];
        printf("%lld %lld",ans1,ans2);
        return 0;
    }
  • 相关阅读:
    CommonJS、AMD、CMD、NodeJs、RequireJS到底有什么联系?
    微信分享链接获取标题和小图片
    如何利用rem在移动端不同设备上让字体自适应大小
    基于VUE.JS的移动端框架Mint UI
    webpack超详细配置, 使用教程(图文)
    webpack一小时入门
    webpack入门教程
    前端构建工具gulpjs的使用介绍及技巧
    better-scroll在vue中的坑
    在vue 中使用Stylus
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676351.html
Copyright © 2011-2022 走看看