zoukankan      html  css  js  c++  java
  • POJ 2987

    题目链接:http://poj.org/problem?id=2987

    Time Limit: 5000MS Memory Limit: 131072K

    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 ≤ ij ≤ 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.

    题意:

    题目给出N个人,M个直属关系;

    N个人每个人都有一个“解雇收益值”,代表公司解雇这个人收益为多少(为负就代表损失);

    M个直属关系:(u, v)代表了,解雇u则必须解雇v;

    求公司最少解雇几个人之后,可获得最大收益,为多少;

    题解:

    显然解雇的人满足闭合图关系,而受益最大则是要求最大点权,故本题就是一个最大权闭合子图;

    参考http://www.cnblogs.com/dilthey/p/7565206.html即可。

    当然,怎么求出被炒的人呢?

    在跑完最大流后,残量网络中超级源点s到与其直接相连的点中:

      如果这条边不满流,就属于图S(分割后的两个图中包含超级源点s的那个图),则是属于被解雇的人,就标记;

      如果这条边满流,就属于割集,则这条边的终点不是解雇的人;

    然后剩下的,由于图S中,除了与s相连的边权值不为INF外,其他必然为INF,必然不满流,而如果走到了连接t的边,又会变成满流,就会的停下来;

    所以只要按着满流与否的条件,DFS下去,不断标记不满流边的终点即可。

    AC代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #include<queue>
      5 #define MAXN 5005
      6 #define MAXM 60005
      7 #define INF 0x3f3f3f3f
      8 typedef long long ll;
      9 using namespace std;
     10 int n,m;
     11 ll sum;
     12 int cnt;
     13 struct Edge{
     14     int u,v;
     15     ll c,f;
     16 };
     17 struct Dinic
     18 {
     19     int s,t;
     20     vector<Edge> E;
     21     vector<int> G[MAXN];
     22     bool vis[MAXN];
     23     int lev[MAXN];
     24     int cur[MAXN];
     25     void init(int l,int r)
     26     {
     27         E.clear();
     28         for(int i=l;i<=r;i++) G[i].clear();
     29     }
     30     void addedge(int from,int to,ll cap)
     31     {
     32         E.push_back((Edge){from,to,cap,0});
     33         E.push_back((Edge){to,from,0,0});
     34         int m=E.size();
     35         G[from].push_back(m-2);
     36         G[to].push_back(m-1);
     37     }
     38     bool bfs()
     39     {
     40         memset(vis,0,sizeof(vis));
     41         queue<int> q;
     42         q.push(s);
     43         lev[s]=0;
     44         vis[s]=1;
     45         while(!q.empty())
     46         {
     47             int now=q.front(); q.pop();
     48             for(int i=0,_size=G[now].size();i<_size;i++)
     49             {
     50                 Edge edge=E[G[now][i]];
     51                 int nex=edge.v;
     52                 if(!vis[nex] && edge.c>edge.f)
     53                 {
     54                     lev[nex]=lev[now]+1;
     55                     q.push(nex);
     56                     vis[nex]=1;
     57                 }
     58             }
     59         }
     60         return vis[t];
     61     }
     62     ll dfs(int now,ll aug)
     63     {
     64         if(now==t || aug==0) return aug;
     65         ll flow=0,f;
     66         for(int& i=cur[now],_size=G[now].size();i<_size;i++)
     67         {
     68             Edge& edge=E[G[now][i]];
     69             int nex=edge.v;
     70             if(lev[now]+1 == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>0)
     71             {
     72                 edge.f+=f;
     73                 E[G[now][i]^1].f-=f;
     74                 flow+=f;
     75                 aug-=f;
     76                 if(aug==0) break;
     77             }
     78         }
     79         return flow;
     80     }
     81     ll maxflow()
     82     {
     83         ll flow=0;
     84         while(bfs())
     85         {
     86             memset(cur,0,sizeof(cur));
     87             flow+=dfs(s,INF);
     88         }
     89         return flow;
     90     }
     91 }dinic;
     92 
     93 bool vis[MAXN];
     94 void dfs(int u)
     95 {
     96     for(int i=0,_size=dinic.G[u].size();i<_size;i++)
     97     {
     98         Edge& e=dinic.E[dinic.G[u][i]];
     99         if(!vis[e.v] && e.c>e.f)
    100         {
    101             vis[e.v]=1;
    102             dfs(e.v);
    103         }
    104     }
    105 }
    106 int main()
    107 {
    108     scanf("%d%d",&n,&m);
    109     sum=0;
    110     dinic.init(0,n+1);
    111     dinic.s=0, dinic.t=n+1;
    112     for(int i=1,w;i<=n;i++)
    113     {
    114         scanf("%d",&w);
    115         if(w>0)
    116         {
    117             sum+=(ll)w;
    118             dinic.addedge(dinic.s,i,w);
    119         }
    120         else if(w<0) dinic.addedge(i,dinic.t,-w);
    121     }
    122     for(int i=1,u,v;i<=m;i++)
    123     {
    124         scanf("%d%d",&u,&v);
    125         dinic.addedge(u,v,INF);
    126     }
    127         //建图完毕
    128     ll max_flow=dinic.maxflow();
    129         //计算出最大流,同时得到残存网络
    130         
    131     memset(vis,0,sizeof(vis));
    132     dfs(dinic.s);//遍历残存网络,找出被解雇的人
    133     cnt=0;
    134     for(int i=1;i<=n;i++) if(vis[i]) cnt++;
    135 
    136     printf("%d %I64d
    ",cnt,sum-max_flow);
    137 }
  • 相关阅读:
    ASP.NET 文件下载
    Asp.net 加密解密类
    ASP.Net 获取服务器信息
    Visual Studio 2013 和 ASP.NET 预览
    Windows Server 2012安装时所需要的KEY
    WordPress主题模板层次和常用模板函数
    小meta的大作用
    《淘宝技术这十年》之LAMP架构的网站
    面试题(八)
    面试题(七)
  • 原文地址:https://www.cnblogs.com/dilthey/p/7565441.html
Copyright © 2011-2022 走看看