首页 > 代码库 > BZOJ 2039: [2009国家集训队]employ人员雇佣

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

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

Time Limit: 20 Sec  Memory Limit: 259 MB
Submit: 1369  Solved: 667
[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

HINT

 

Source

版权所有者: 林衍凯

[Submit][Status][Discuss]

 

 

建图求最小割:

假设一开始获得了所有的Wij,ans = ΣWij。

加入使用一个经理,产生代价是Costi,从源点向该点连Costi的边。

两个经理之间互相影响,如果在两人之间断开,及选取两人中的一个,那么将失去一开始得到的Wij,并且还会损失Wij的竞争代价,所以连边2*Wij。

我们也可以直接选择放弃一个经理,失去所有其本算在答案中的贡献,即ΣWij,其中j=1..n。

最终ans - 最小割就是答案。

 

  1 #include <cstdio>  2 #include <cstring>  3   4 const int siz = 4000010;  5 const int inf = 1000000007;  6   7 int n;  8   9 int tot; 10 int s, t; 11 int hd[siz]; 12 int to[siz]; 13 int fl[siz]; 14 int nt[siz]; 15  16 inline void add(int u, int v, int f) 17 { 18 //    printf("add %d %d %d\n", u, v, f); 19     nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; hd[u] = tot++; 20     nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; hd[v] = tot++; 21 } 22  23 int dep[siz]; 24  25 inline bool bfs(void) 26 { 27     static int que[siz]; 28     static int head, tail; 29      30     memset(dep, 0, sizeof(dep)); 31     dep[que[head = 0] = s] = tail = 1; 32      33     while (head != tail) 34     { 35         int u = que[head++], v; 36         for (int i = hd[u]; ~i; i = nt[i]) 37             if (fl[i] && !dep[v = to[i]]) 38                 dep[que[tail++] = v] = dep[u] + 1; 39     } 40      41     return dep[t]; 42 } 43  44 int cur[siz]; 45  46 inline int min(int a, int b) 47 { 48     return a < b ? a : b; 49 } 50  51 int dfs(int u, int f) 52 { 53     if (u == t || !f) 54         return f; 55      56     int used = 0, flow, v; 57      58     for (int i = hd[u]; ~i; i = nt[i]) 59         if (fl[i] && dep[v = to[i]] == dep[u] + 1) 60         { 61             flow = dfs(v, min(f - used, fl[i])); 62             used += flow; 63             fl[i] -= flow; 64             fl[i ^ 1] += flow;  65             if (used == f) 66                 return f; 67             if (fl[i]) 68                 cur[u] = i; 69         } 70          71     if (!used) 72         dep[u] = 0; 73      74     return used; 75 } 76  77 inline int maxFlow(void) 78 { 79     int maxFlow = 0, newFlow; 80      81     while (bfs()) 82     { 83         for (int i = s; i <= t; ++i) 84             cur[i] = hd[i]; 85              86         while (newFlow = dfs(s, inf)) 87             maxFlow += newFlow; 88     } 89              90     return maxFlow; 91 } 92  93 int ans; 94 int sum; 95  96 signed main(void) 97 { 98     scanf("%d", &n); 99     100     s = 0, t = n + 1;101     102     memset(hd, -1, sizeof(hd));103     104     for (int i = 1, x; i <= n; ++i)105         scanf("%d", &x), add(s, i, x);106         107     for (int i = 1; i <= n; ++i)108     {109         sum = 0;110         111         for (int j = 1; j <= n; ++j)112         {113             int x; scanf("%d", &x);114             ans += x;115             sum += x;116             if (i != j)117                 add(i, j, x << 1);118         }119         120         add(i, t, sum);121     }122         123     printf("%d\n", ans - maxFlow());124 }

 

@Author: YouSiki

 

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