[题解]bzoj2039(2009国家集训队)employ人员雇佣

来源:互联网 发布:深圳返享网络 编辑:程序博客网 时间:2024/05/19 13:30

Description

作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司。这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j。当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他。 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响,使得所赚得的利润减少Ei,j(注意:这里的Ei,j与上面的Ei,j 是同一个)。 作为一个效率优先的人,小L想雇佣一些人使得净利润最大。你可以帮助小L解决这个问题吗?

Input

第一行有一个整数N<=1000表示经理的个数 第二行有N个整数Ai表示雇佣每个经理需要花费的金钱 接下来的N行中一行包含N个数,表示Ei,j,即经理i对经理j的了解程度。(输入满足Ei,j=Ej,i)

Output

第一行包含一个整数,即所求出的最大值。

Sample Input

3
3 5 100
0 6 1
6 0 2
1 2 0

Sample Output

1

【数据规模和约定】
20%的数据中N<=10
50%的数据中N<=100
100%的数据中 N<=1000, Ei,j<=maxlongint, Ai<=maxlongint

Solution

        网络流最小割。构图首先按照惯例,S向每个人连这个人所能造成的所有的价值(雇佣所有人的情况),每个人向T连雇佣他的花费。关键问题是如何处理经理相互影响的状况。当两个经理一个选一个不选的时候,我们不仅要割掉一个经理的价值和另一个经理的雇佣费用,还需要承受两个经理之间的影响后果。相当于我们不但不能获得E[i,j]的收益,还要倒扣E[i,j]的收益,相当于割掉一条边权为2*E[i,j]的边。所以我们这么构图:

然后跑一边最大流,用所有人都雇佣的最大收益减去最大流就得到答案。

代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<climits>using namespace std; inline int read(){    int x=0,f=1;char ch=getchar();    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';    return x*f;} typedef long long LL;const int maxn=1010;struct edge{    int to,next,same;    LL size;}e[maxn*maxn*3];const LL oo=LONG_LONG_MAX;int E[maxn][maxn],n,a[maxn],num=0,head[maxn];int que[maxn],dep[maxn],cur[maxn];LL sum[maxn],ans=0; void adde(int u,int v,LL w){    e[++num].to=v;e[num].size=w;    e[num].next=head[u];    head[u]=num;}void add(int u,int v,LL w){    adde(u,v,w);e[num].same=num+1;    adde(v,u,0);e[num].same=num-1;}bool bfs(){    memset(que,0,sizeof que);    memset(dep,0,sizeof dep);    int qhead=0,tail=1;    que[1]=0;dep[0]=1;    while(qhead<tail){        int now=que[++qhead];        for(int i=head[now];i;i=e[i].next){            if(!dep[e[i].to]&&e[i].size){                que[++tail]=e[i].to;                dep[e[i].to]=dep[now]+1;                if(e[i].to==n+1)return true;            }        }    }    return false;}LL dfs(int x,LL flow){    if(x==n+1||(!flow))return flow;    LL temp;    for(int &i=cur[x];i;i=e[i].next){        if(dep[e[i].to]==dep[x]+1&&(temp=dfs(e[i].to,min(flow,e[i].size)))){            e[i].size-=temp;            e[e[i].same].size+=temp;            return temp;        }    }    return 0;}void Dinic(){    while(bfs()){        int flow;        memcpy(cur,head,sizeof head);        while((flow=dfs(0,oo))){            ans-=flow;        }    }} int main(){    n=read();    for(int i=1;i<=n;i++){        a[i]=read();        add(i,n+1,a[i]);    }    for(int i=1;i<=n;i++){        for(int j=1;j<=n;j++){            E[i][j]=read();            if(i!=j)add(i,j,E[i][j]<<1);            sum[i]+=E[i][j];        }    }    for(int i=1;i<=n;i++){        add(0,i,sum[i]);        ans+=sum[i];    }    Dinic();    printf("%lld\n",ans);    return 0;}


0 0
原创粉丝点击