码迷,mamicode.com
首页 > 其他好文 > 详细

POJ_2987_Firing(最大流+最大权闭合图)

时间:2016-04-27 17:04:53      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:

描述


http://poj.org/problem?id=2987

要炒员工鱿鱼,炒了一个人,他的下属一定被炒.给出每个人被炒后公司的收益(负值表示亏损),问怎样炒公司收益最大,以及这种方法炒了几个人.(先输出人数)

 

分析


求最大收益是用最大权闭合图.要炒一个人,他的下属也要被炒,那么边由上司连向下属,求最大权闭合图即可.

求炒了几个人实际是就是求先前求出来的那个最大权闭合图中点的个数.最大权闭合图对应的是最小割,而最小割中的边都是满流的,所以从源点出发无法到达闭合图的补集(即T),并且由于是闭合图,所以图中的边都不属于割,这样闭合图中就没有流量,从源点出发可以到达闭合图中的每一个点.

注意:

1.要用long long.

ps.f[S,T]=|f|,即整个图的流等于流过割的流,这样这道题中,f=fmax=cmin,又f=f[S,T],所以f[S,T]=cmin,也就是流过最小割的流等于最小割的容量,所以满流了.

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define rep(i,n) for(int i=0;i<(n);i++)
#define for1(i,a,n) for(int i=(a);i<=(n);i++)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getnum()
#define ll long long
using namespace std;

const int maxn=5000+10,INF=0x7fffffff;
int n,m;
ll sumw;
int level[maxn],iter[maxn];
bool vis[maxn];
struct edge
{
    int to,cap,rev;
    edge() {}
    edge(int a,ll b,int c) : to(a),cap(b),rev(c) {}
};
vector <edge> g[maxn];

inline int getnum()
{
    int r=0,k=1; char c;
    for(c=getchar();c<0||c>9;c=getchar()) if(c==-) k=-1;
    for(;c>=0&&c<=9;c=getchar()) r=r*10+c-0;
    return r*k;
}

void add_edge(int from,int to,int cap)
{
    g[from].push_back(edge(to,cap,g[to].size()));
    g[to].push_back(edge(from,0,g[from].size()-1));
}

void bfs(int s)
{
    CC(level,-1);
    level[s]=0;
    queue <int> q;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front(); q.pop();
        rep(i,g[t].size())
        {
            edge e=g[t][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[t]+1;
                q.push(e.to);
            }
        }
    }
}

int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++)
    {
        edge &e=g[v][i];
        if(e.cap>0&&level[e.to]>level[v])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                g[e.to][e.rev].cap+=d;
                return d;
            }
        }
        
    }
    return 0;
}

ll max_flow(int s,int t)
{
    ll flow=0;
    bfs(s);
    while(level[t]>0)
    {
        int f;
        CC(iter,0);
        while((f=dfs(s,t,INF))>0) flow+=f;
        bfs(s);
    }
    return flow;
}

int DFS(int v)
{
    vis[v]=true;
    int ans=1;
    rep(i,g[v].size())
    {
        edge e=g[v][i];
        if(!vis[e.to]&&e.cap>0) ans+=DFS(e.to);
    }
    return ans;
}

void init()
{
    read(n); read(m);
    for1(i,1,n)
    {
        int w; read(w);
        if(w>0)
        {
            sumw+=w;
            add_edge(0,i,w);
        }
        else
        {
            add_edge(i,n+1,-w);
        }
    }
    for1(i,1,m)
    {
        int a,b; read(a); read(b);
        add_edge(a,b,INF);
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("firing.in","r",stdin);
    freopen("firing.out","w",stdout);
#endif
    init();
    ll ans=sumw-max_flow(0,n+1);
    printf("%d %lld\n",DFS(0)-1,ans);
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("firing.out");
#endif
    return 0;
}

 

 

POJ_2987_Firing(最大流+最大权闭合图)

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5439457.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!