BZOJ 2039: [2009国家集训队]employ人员雇佣
Posted You Siki
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2039: [2009国家集训队]employ人员雇佣相关的知识,希望对你有一定的参考价值。
2039: [2009国家集训队]employ人员雇佣
Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 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 5 100
0 6 1
6 0 2
1 2 0
Sample Output
【数据规模和约定】
20%的数据中N<=10
50%的数据中N<=100
100%的数据中 N<=1000, Ei,j<=maxlongint, Ai<=maxlongint
HINT
Source
建图求最小割:
假设一开始获得了所有的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人员雇佣的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2039: [2009国家集训队]employ人员雇佣
[Bzoj2039][2009国家集训队]employ人员雇佣(最小割)
bzoj2039: [2009国家集训队]employ人员雇佣(最小割)
BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割