Topic link: http: //poj.org/problem id = 2987?
Subject to the effect: A company wants to layoffs, downsizing of the standard is that if someone is cut, its subsidiary will be cut, and so on, everyone has a contribution, if positive, will increase the company's laid off earnings, if negative, laid off will reduce the company's earnings, layoffs and asked how can we make a final contribution of maximum and minimum number of people laid off?
Idea: Because delete a boss, employees will leave, so in the end people will seek deletion is a closed figure, that is, the right to seek the most closed figure. Wherein s set point is the point where the maximum weight of the closure in FIG.
1. FIG entire previously recorded, and all punctual values of the weights;
2. correspondence flow network, seeking maximum flow, maximum flow is equal in value to the minimum cut, so we get a minimum cut st Flow Network;
3. "All and "subtracting" ST minimum cut ", i.e., the right to obtain the maximum value of the right sub-picture is closed and punctual weights.
4. FIG minimum cut point is cut off points
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL maxn=1e5+10;
const LL maxm=2e5+10;
struct E
{
LL v; //每一条边指向的点
LL next;//指向对应点的前一条边
LL w; //每一条边的残量
}e[maxm];
LL s, t;//源点和汇点
LL cut;//边的数量,从0开始编号
LL head[maxm];//每一个点最后一条边的编号
LL d[maxn];//分层图中标记深度
LL inf=(1ll<<60);
LL cur[maxn];//cur就是记录当前点u循环到了哪一条边
LL n, m;
void init()
{
cut=-1;
memset(head, -1, sizeof(head));
}
void addEdge(LL u, LL v, LL w)
{
cut++;
e[cut].next=head[u];
e[cut].v=v;
e[cut].w=w;
head[u]=cut;
}
void add(LL u, LL v, LL w)
{
addEdge(u, v, w);
addEdge(v, u, 0);
}
LL bfs()
{
queue<LL> q;
while(!q.empty())
{
q.pop();
}
memset(d, 0, sizeof(d));
d[s]=1;//源点深度为1
q.push(s);
while(!q.empty())
{
LL u=q.front();
q.pop();
for(LL i=head[u];i!=-1;i=e[i].next)
{
LL v=e[i].v, w=e[i].w;
if(w>0&&d[v]==0)//若该残量不为0,且V[i]还未分配深度,则给其分配深度并放入队列
{
d[v]=d[u]+1;
q.push(v);
}
}
}
if(d[t]==0)//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
{
return 0;
}
return 1;
}
LL dfs(LL u, LL dis)//u是当前节点,dist是当前流量
{
if(u==t)
{
return dis;//当已经到达汇点,直接返回
}
for(LL &i=cur[u];i!=-1;i=e[i].next)
{
LL v=e[i].v, w=e[i].w;
if((d[v]==d[u]+1)&&w!=0)//注意这里要满足分层图和残量不为0两个条件
{
LL di=dfs(v, min(dis, w));//向下增广
if(di>0)//若增广成功
{
e[i].w-=di;//正向边减
e[i^1].w+=di;//反向边加
return di;//向上传递
}
}
}
return 0;//否则说明没有增广路,返回0
}
LL Dinic()
{
LL ans=0;//记录最大流量
while (bfs())
{
/*******************************/
for(LL i=s;i<=t;i++)//每一次建立完分层图后都要把cur置为每一个点的第一条边
{
cur[i]=head[i];
}
/********************************/
while (LL d=dfs(s,inf))
{
ans+=d;
}
}
return ans;
}
queue<int> q;
LL minzxg(){//不在最大权闭合子图的点数
LL ans=0;
memset(d, 0, sizeof(d));
q.push(s);
d[s]=1;
while(!q.empty()){
LL u=q.front();
q.pop();
ans++;
for(LL i=head[u];i!=-1;i=e[i].next){
LL v=e[i].v, w=e[i].w;
if(d[v]==0&&w>0){
d[v]=1;
q.push(v);
}
}
}
return ans-1;//-源点
}
int main()
{
while(~scanf("%lld%lld",&n,&m))
{
init();
s=0, t=n+1;
LL u, v, w, ans=0;
for(int i=1; i<=n; i++){
scanf("%lld", &w);
if(w>=0){
ans+=w;
add(s, i, w);
}
else{
add(i, t, -w);
}
}
for(int i=0;i<m;i++)
{
LL u, v;
scanf("%lld%lld",&u,&v);
add(u, v, inf);
}
LL ds=Dinic();
printf("%lld %lld\n",minzxg(), ans-ds);
}
return 0;
}