bzoj2039: [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
 
题解:
这题没有坑,直接二元组建图
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 1005
 7 #define maxm 6000000
 8 #define inf 4557430888798830399LL
 9 using namespace std;
10 typedef long long int64;
11 char ch;
12 bool ok;
13 void read(int &x){
14     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
15     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
16     if (ok) x=-x;
17 }
18 void read(int64 &x){
19     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
20     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
21     if (ok) x=-x;
22 }
23 int n;
24 int64 sum,x;
25 struct flow{
26     int s,t,tot,now[maxn],son[maxm],pre[maxm];
27     int64 val[maxm];
28     int dis[maxn],head,tail,list[maxn];
29     bool bo[maxn];
30     void init(){s=0,t=n+1,tot=1,memset(now,0,sizeof(now));}
31     void put(int a,int b,int64 c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
32     void add(int a,int b,int64 c){put(a,b,c),put(b,a,0);}
33     bool bfs(){
34         memset(bo,0,sizeof(bo));
35         head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1;
36         while (head<tail){
37             int u=list[++head];
38             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
39                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
40         }
41         return bo[t];
42     }
43     int64 dfs(int u,int64 rest){
44         if (u==t) return rest;
45         int64 ans=0;
46         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
47             if (val[p]&&dis[v]==dis[u]+1){
48                 int64 d=dfs(v,min(rest,val[p]));
49                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
50             }
51         if (!ans) dis[u]=-1;
52         return ans;
53     }
54     int64 dinic(){
55         int64 ans=0;
56         while (bfs()) ans+=dfs(s,inf);
57         return ans;
58     }
59 }f;
60 int main(){
61     read(n),f.init();
62     for (int i=1;i<=n;i++) read(x),f.add(f.s,i,x<<1);
63     for (int i=1;i<=n;i++) for (int j=1;j<=n;j++){
64         read(x);
65         if (i>j){
66             sum+=(x<<1);
67             f.add(i,j,x<<2),f.add(j,i,x<<2);
68             f.add(i,f.t,x<<1),f.add(j,f.t,x<<1);
69         }
70     }
71     printf("%lld\n",sum-(f.dinic()>>1));
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/chenyushuo/p/5146734.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值