BZOJ2039 [2009国家集训队]employ人员雇佣(DInic算法求最大流)

题意:

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

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

题解:

源点向每个经理建边,容量为经理的价格。

经理之间建边,容量为了解程度的两倍

同时统计所有经理之间了解程度之和。

这个总和减去全图最大流就是答案

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e6;
const int inf=1e9;
int head[maxn];
int tol;
struct node {
    int u;
    int v;
    int w;
    int next;
}edge[maxn];
void addedge (int u,int v,int w) {
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].w=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].u=v;
    edge[tol].v=u;
    edge[tol].w=0;
    edge[tol].next=head[v];
    head[v]=tol++;
}


int dep[maxn];
int inque[maxn];
int vi;
int cur[maxn];
int maxflow=0;
int s,t;
bool bfs () {
    for (int i=0;i<=t;i++) 
        cur[i]=head[i],dep[i]=inf,inque[i]=0;
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u=q.front();
        q.pop();
        inque[u]=0;
        for (int i=head[u];i!=-1;i=edge[i].next) {
            int v=edge[i].v;
            if (dep[v]>dep[u]+1&&edge[i].w) {
                dep[v]=dep[u]+1;
                if (inque[v]==0) {
                    q.push(v);
                    inque[v]=1;
                } 
            }
        }
    }
    if (dep[t]!=inf) return 1;
    return 0;
}
int dfs (int u,int flow) {
    int increase=0;
    if (u==t) {
        vi=1;
        maxflow+=flow;
        return flow;
    }
    int used=0;
    for (int i=cur[u];i!=-1;i=edge[i].next) {
        cur[u]=i;
        int v=edge[i].v;
        if (edge[i].w&&dep[v]==dep[u]+1) {
            if (increase=dfs(v,min(flow-used,edge[i].w))) {
                used+=increase;
                edge[i].w-=increase;
                edge[i^1].w+=increase;
                if (used==flow) break;
            }
        }
    }
    return used;
}
int Dinic () {
    while (bfs()) {
        vi=1;
        while (vi==1) {
            vi=0;
            dfs(s,inf);
        }
    } 
    return maxflow;
}
int main () {
    int N;
    int ans=0;
    scanf("%d",&N);
    s=0,t=N+1;
    memset(head,-1,sizeof(head));
    for (int i=1;i<=N;i++) {
        int x;
        scanf("%d",&x);
        addedge(s,i,x);
    }
    for (int i=1;i<=N;i++) {
        int sum=0;
        for (int j=1;j<=N;j++) {
            int x;
            scanf("%d",&x);
            ans+=x;
            sum+=x;
            if (i!=j) addedge(i,j,x*2);
        }
        addedge(i,t,sum);
    }
    printf("%d\n",ans-Dinic());
} 

猜你喜欢

转载自www.cnblogs.com/zhanglichen/p/12557922.html