bzoj2039

两盒软妹~` 提交于 2020-02-16 23:25:16

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;
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!