poj 2987 Firing 最大权闭合图

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

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?

 

题目描述:公司解雇员工,每个员工有一个权值,可正可负可为零(对公司而言等同于员工对公司的贡献力)。然后给出一些员工上下级的关系,如果解雇一个员工(比如经理主管之类的),那么他手下的员工都会被解雇,问对公司获利最大的解雇计划以及解雇员工人数。

算法分析:每个员工看作一个点,新增源点from和汇点to,from连边权值为正的点,边权为该权值;to连边权值为负的点,边权为权值的绝对值;员工之间的上下级也连边,边权为无穷大。最后最大权闭合图=权值为正的点的权值的和-最小割。

最大权闭合图参考资料:

胡伯涛 《最小割模型在信息学竞赛中的应用》

大牛博客:【网络流】最大权闭合图

  1 #include<iostream>

  2 #include<cstdio>

  3 #include<cstring>

  4 #include<cstdlib>

  5 #include<cmath>

  6 #include<algorithm>

  7 #include<vector>

  8 #include<queue>

  9 #define inf 0x7fffffff

 10 using namespace std;

 11 typedef long long LL;

 12 const int maxn=5000+10;

 13 const int M = 25000000+10;

 14 

 15 int n,m,from,to;

 16 struct node

 17 {

 18     int v,flow;

 19     int next;

 20 }edge[M*3];

 21 int head[maxn],edgenum;

 22 

 23 void add(int u,int v,int flow)

 24 {

 25     edge[edgenum].v=v ;edge[edgenum].flow=flow ;

 26     edge[edgenum].next=head[u] ;head[u]=edgenum++ ;

 27 

 28     edge[edgenum].v=u ;edge[edgenum].flow=0 ;

 29     edge[edgenum].next=head[v] ;head[v]=edgenum++ ;

 30 }

 31 

 32 int d[maxn];

 33 int bfs()

 34 {

 35     memset(d,0,sizeof(d));

 36     d[from]=1;

 37     queue<int> Q;

 38     Q.push(from);

 39     while (!Q.empty())

 40     {

 41         int u=Q.front() ;Q.pop() ;

 42         for (int i=head[u] ;i!=-1 ;i=edge[i].next)

 43         {

 44             int v=edge[i].v;

 45             if (!d[v] && edge[i].flow)

 46             {

 47                 d[v]=d[u]+1;

 48                 Q.push(v);

 49                 if (v==to) return 1;

 50             }

 51         }

 52     }

 53     return 0;

 54 }

 55 

 56 int dfs(int u,int flow)

 57 {

 58     if (u==to || flow==0) return flow;

 59     int cap=flow;

 60     for (int i=head[u] ;i!=-1 ;i=edge[i].next)

 61     {

 62         int v=edge[i].v;

 63         if (d[v]==d[u]+1 && edge[i].flow)

 64         {

 65             int x=dfs(v,min(edge[i].flow,cap));

 66             edge[i].flow -= x;

 67             edge[i^1].flow += x;

 68             cap -= x;

 69             if (cap==0) return flow;

 70         }

 71     }

 72     return flow-cap;

 73 }

 74 

 75 LL dinic()

 76 {

 77     LL ans=0;

 78     while (bfs()) ans += dfs(from,inf);

 79     return ans;

 80 }

 81 

 82 int vis[maxn];

 83 void dfs2(int u)

 84 {

 85     if (u==to) return ;

 86     vis[u]=1;

 87     for (int i=head[u] ;i!=-1 ;i=edge[i].next)

 88         if (edge[i].flow>0 && !vis[edge[i].v ])

 89             dfs2(edge[i].v);

 90 }

 91 

 92 int main()

 93 {

 94     while (scanf("%d%d",&n,&m)!=EOF)

 95     {

 96         memset(head,-1,sizeof(head));

 97         edgenum=0;

 98         from=n+1;

 99         to=from+1;

100         int a,b;

101         LL sum=0;

102         for (int i=1 ;i<=n ;i++)

103         {

104             scanf("%d",&a);

105             if (a>0) {sum += a ;add(from,i,a) ;}

106             else add(i,to,-a);

107         }

108         for (int i=0 ;i<m ;i++)

109         {

110             scanf("%d%d",&a,&b);

111             add(a,b,inf);

112         }

113         sum=sum-dinic();

114         memset(vis,0,sizeof(vis));

115         dfs2(from);

116         int ans=0;

117         for (int i=1 ;i<=n ;i++) if (vis[i]) ans++;

118         printf("%d %I64d\n",ans,sum);

119     }

120     return 0;

121 }

 

你可能感兴趣的:(poj)