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\n",ans-flow);

150     }

151     return 0;

152 }
View Code

 

你可能感兴趣的:(poj)