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
", 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
", ans - maxFlow());
124 }

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6249508.html