zoukankan      html  css  js  c++  java
  • BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割

    BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割

    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


    转化为损失最少的最小割模型。

    建立$S$,$T$分别表示选或不选,便于用$S$,$T$割集表示方案。

    然后设两个经理$i$和$j$,连这样几条边$S->i(x1),S->j(x2),i->j(x3),i->T(x4),j->T(x5)$,括号内代表容量,$x$为设的未知数。

    假设$i$和$j$都选,那么要割掉到$T$的两条边$x4+x5$。假设都不选,则需要割掉$S$连出的两条边$x1+x2$。

    $i$选$j$不选,则需要割掉$x2+x3+x4$三条边。

    然后分别和真正的收益对应一下,可以得到$x1=sumlimits_{k=1}^{n}e[i][k]$ $x3=2*e[i][j]$ $x4=a[i]$。

    于是建图跑最小割即可。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline char nc() {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd() {
        register int x=0;
        register char s=nc();
        while(s<'0'||s>'9') s=nc();
        while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
        return x;
    }
    #define N 1050
    #define M 3000050
    #define S (n+1)
    #define T (n+2)
    #define inf (1ll<<60)
    int n,a[N],e[N][N];
    struct Dinic {
        int head[N],to[M],nxt[M],cnt;
        int dep[N],Q[N],l,r;
        ll flow[M],sum;
        inline void add(int u,int v,ll f) {
            to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
            to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
        }
        bool bfs() {
            memset(dep,0,sizeof(dep));
            l=r=0; Q[r++]=S; dep[S]=1;
            while(l<r) {
                int x=Q[l++],i;
                for(i=head[x];i;i=nxt[i]) {
                    if(!dep[to[i]]&&flow[i]) {
                        dep[to[i]]=dep[x]+1;
                        if(to[i]==T) return 1;
                        Q[r++]=to[i];
                    }
                }
            }
            return 0;
        }
        ll dfs(int x,ll mf) {
            if(x==T) return mf;
            ll nf=0;
            int i;
            for(i=head[x];i;i=nxt[i]) {
                if(dep[to[i]]==dep[x]+1&&flow[i]) {
                    ll tmp=dfs(to[i],min(mf-nf,flow[i]));
                    if(!tmp) dep[to[i]]=0;
                    nf+=tmp;
                    flow[i]-=tmp;
                    flow[i^1]+=tmp;
                    if(nf==mf) break;
                }
            }
            return nf;
        }
        void dinic() {
            ll f;
            while(bfs()) while((f=dfs(S,inf))!=0) sum-=f;
            printf("%lld
    ",sum);
        }
    }G;
    int main() {
        G.cnt=1;
        n=rd();
        int i,j;
        for(i=1;i<=n;i++) a[i]=rd();
        for(i=1;i<=n;i++) {
            ll now=0;
            for(j=1;j<=n;j++) {
                e[i][j]=rd();
                G.sum+=e[i][j];
                now+=e[i][j];
                G.add(i,j,2*e[i][j]);
            }
            G.add(S,i,now);
            G.add(i,T,a[i]);
        }
        G.dinic();
    }
    
  • 相关阅读:
    C++ Tr1中的正則表達式
    html中#include file的使用方法
    InstallShield12豪华版破解版下载|InstallShield下载|软件打包工具
    linux-多线程
    使用 ArcGIS Online和APP进行监控操作和数据采集
    西藏印象:时光篇
    西藏印象:夜色篇
    西藏印象:蓝白篇
    hex2bin
    使用openssl的aes各种加密算法
  • 原文地址:https://www.cnblogs.com/suika/p/9032522.html
Copyright © 2011-2022 走看看