zoukankan      html  css  js  c++  java
  • poj 2987 最大权闭合图

    Language:
    Firing
    Time Limit: 5000MS   Memory Limit: 131072K
    Total Submissions: 8744   Accepted: 2631

    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 individuallybi (|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.
     
    很基础的最大权闭合图
     
      1 #include<iostream>
      2 #include<queue>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<climits>
      6 #define MAXE 65100*2
      7 #define MAXP 5100
      8 #define Max(a,b) a>b?a:b
      9 #define Min(a,b) a<b?a:b
     10 using namespace std;
     11 struct Edge
     12 {
     13     long long int s,t,next;
     14     long long f;
     15 } edge[MAXE];
     16 long long int head[MAXP];
     17 long long int cur[MAXP];
     18 long long int pre[MAXP];
     19 long long int stack[MAXE];
     20 long long int dep[MAXP];
     21 long long int ent;
     22 long long int n,m,s,t,cot;
     23 void add(long long int start,long long int last,long long int f)
     24 {
     25     edge[ent].s=start;
     26     edge[ent].t=last;
     27     edge[ent].f=f;
     28     edge[ent].next=head[start];
     29     head[start]=ent++;
     30     edge[ent].s=last;
     31     edge[ent].t=start;
     32     edge[ent].f=0;
     33     edge[ent].next=head[last];
     34     head[last]=ent++;
     35 }
     36 bool bfs(long long int S,long long int T)
     37 {
     38     memset(pre,-1,sizeof(pre));
     39     pre[S]=0;
     40     queue<long long int>q;
     41     q.push(S);
     42     while(!q.empty())
     43     {
     44         long long int temp=q.front();
     45         q.pop();
     46         for(long long int i=head[temp]; i!=-1; i=edge[i].next)
     47         {
     48             long long int temp2=edge[i].t;
     49             if(pre[temp2]==-1&&edge[i].f)
     50             {
     51                 pre[temp2]=pre[temp]+1;
     52                 q.push(temp2);
     53             }
     54         }
     55     }
     56     return pre[T]!=-1;
     57 }
     58 long long int dinic(long long int start,long long int last)
     59 {
     60     long long int flow=0,now;
     61     while(bfs(start,last))
     62     {
     63         long long int top=0;
     64         memcpy(cur,head,sizeof(head));
     65         long long int u=start;
     66         while(1)
     67         {
     68             if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流
     69             {
     70                 long long int minn=INT_MAX;
     71                 for(long long int i=0; i<top; i++)
     72                 {
     73                     if(minn>edge[stack[i]].f)
     74                     {
     75                         minn=edge[stack[i]].f;
     76                         now=i;
     77                     }
     78                 }
     79                 flow+=minn;
     80                 for(long long int i=0; i<top; i++)
     81                 {
     82                     edge[stack[i]].f-=minn;
     83                     edge[stack[i]^1].f+=minn;
     84                 }
     85                 top=now;
     86                 u=edge[stack[top]].s;
     87             }
     88             for(long long int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边
     89                 if(edge[i].f&&pre[edge[i].t]==pre[u]+1)
     90                     break;
     91             if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯
     92             {
     93                 if(top==0)break;
     94                 pre[u]=-1;
     95                 u=edge[stack[--top]].s;
     96             }
     97             else//如果找到了继续运行
     98             {
     99                 stack[top++]=cur[u];
    100                 u=edge[cur[u]].t;
    101             }
    102         }
    103     }
    104     return flow;
    105 }
    106 void dfs(long long int u)
    107 {
    108     cot++;
    109     dep[u]=1;
    110     for(long long int i=head[u];i!=-1;i=edge[i].next)
    111     {
    112         long long int v=edge[i].t;
    113         if(!dep[v]&&edge[i].f>0)
    114         {
    115             dfs(v);
    116         }
    117     }
    118 }
    119 int main()
    120 {
    121     while(~scanf("%lld%lld",&n,&m))
    122     {
    123         s=0;
    124         t=n+1;
    125         ent=0;
    126         long long int cost,u,v;
    127         long long int ans=0;
    128         memset(head,-1,sizeof(head));
    129         for(int i=1; i<=n; i++)
    130         {
    131             scanf("%lld",&cost);
    132             if(cost>0)
    133             {
    134                 add(s,i,cost);
    135                 ans+=cost;
    136             }
    137             else add(i,t,-cost);
    138         }
    139         for(int i=1; i<=m; i++)
    140         {
    141             scanf("%lld%lld",&u,&v);
    142             add(u,v,INT_MAX);
    143         }
    144         memset(dep,0,sizeof(dep));
    145         long long int flow=dinic(s,t);
    146         cot=0;
    147         dfs(s);
    148         printf("%lld ",cot-1);
    149         printf("%lld
    ",ans-flow);
    150     }
    151     return 0;
    152 }
    View Code
  • 相关阅读:
    C#基础(WinForm窗体的单例模式,避免窗体被实例化多次)
    NPOI基础入门(旧版本)
    SQLite数据插入异常
    EClipse开发NDK流程
    git 常用命令
    6.0权限的简单实用
    MVVM模式
    去掉所有字符里面的空格换行符等
    高逼格的实现WiFi共享,不安装第三方wifi共享软件,两种方式实现开启wifi的功能
    常用的正则表达表达式以及简单用法
  • 原文地址:https://www.cnblogs.com/lthb/p/4485876.html
Copyright © 2011-2022 走看看