zoukankan      html  css  js  c++  java
  • bzoj2039

    2039: [2009国家集训队]employ人员雇佣

    Time Limit: 20 Sec  Memory Limit: 259 MB
    Submit: 1791  Solved: 869
    [Submit][Status][Discuss]

    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

    推荐一个blog,写的很清晰

    大致学会了一类最小割的应用吧。

    最小割找矛盾关系,和二分图类似,最小割之后分成了S部T部,S部表示一边,T部表示另一边。这种东西可以用来解决两两对立关系的选择。

    答案一般为 sum-最小割,因为最小割表示的是一种损失最小的选择

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    #define ll long long
    #define N 1005
    using namespace std;
    int n,m,tot,S,T,hd[N],d[N],cur[N],vis[N],cos[N],mp[N][N];ll sum[N],res;
    struct edge{int v,next;ll cap;}e[N*N*4];
    void adde(int u,int v,ll c){
        e[tot].v=v;
        e[tot].next=hd[u];
        e[tot].cap=c;
        hd[u]=tot++;
    }
    bool bfs(){
        queue<int>q;
        memset(vis,0,sizeof(vis));
        d[S]=0;vis[S]=1;q.push(S);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=hd[u];~i;i=e[i].next){
                int v=e[i].v;
                if(e[i].cap&&!vis[v]){
                    vis[v]=1;
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[T];
    }
    ll dfs(int u,ll a){
        if(u==T||!a)return a;
        ll fl=0,f;
        for(int &i=cur[u];~i;i=e[i].next){
            int v=e[i].v;
            if(e[i].cap&&d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap,a)))){
                fl+=f;a-=f;e[i].cap-=f;
                e[i^1].cap+=f;if(!a)break;
            }
        }
        return fl;
    }
    ll dinic(){
        ll flow=0;
        while(bfs()){
            for(int i=S;i<=T;i++)cur[i]=hd[i];
            flow+=dfs(S,inf);
        }
        return flow;
    }
    int main(){
    #ifdef wsy
        freopen("data.in","r",stdin);
    #else
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    #endif
        memset(hd,-1,sizeof(hd));
        scanf("%d",&n);
        S=0;T=n+1;
        for(int i=1;i<=n;i++)scanf("%d",&cos[i]);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            scanf("%d",&mp[i][j]);
            sum[i]+=mp[i][j];
        }
        for(int i=1;i<=n;i++){
            adde(S,i,sum[i]);
            adde(i,S,0);
            adde(i,T,cos[i]);
            adde(T,i,0);
            res+=sum[i];
        }
        for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            adde(i,j,(ll)2*mp[i][j]);
            adde(j,i,(ll)2*mp[i][j]);
        }
        ll flow=dinic();
        printf("%lld",res-flow);
        return 0;
    }
  • 相关阅读:
    C#
    C#
    C#
    C#
    C#
    C#
    系统工具
    远程登录
    文件传输服务
    软件安装
  • 原文地址:https://www.cnblogs.com/wsy01/p/7928182.html
Copyright © 2011-2022 走看看