• BZOJ 2039:[2009国家集训队]employ人员雇佣(最小割)


    http://www.lydsy.com/JudgeOnline/problem.php?id=2039

    题意:中文题意。

    思路:一开始想着和之前做的最大权闭合图有点像,但是如果把边全部当成点的话,那么点也太多了。

    对于这种选和不选的方案问题,还是一样用最小割来解决,求最小的损失收益,然后用能够得到的总收益去减去最小割的值就是答案。思维模式是:将S集或者T集的某一边当成是选择的,另一边当成是不选择的,根据这样去连边,就可能更容易想到建图方案。

    在这题里面,我把T集当成是选择的人,把S集当成是不选择的人。这样的话如果选择一个人,那么就损失了雇佣他的钱,于是将A[i]和S相连,代表如果不割这条边的话,那么它就会划入S集。同理如果不雇佣一个人,损失的E[i]和T相连,代表如果不割这条边的话,那么它就划入T集,代表选择这个人。有了上面这两个主要的建边,接下来就很容易想到将人与人之间连一条容量为互相的贡献E[i,j]*2(题意)的无向边,代表如果选了i,那么可以对j作出E[i,j]的贡献,选j同理。

    这样图的点数其实就是人数+2而已。记得要开longlong,还有损失的E[i]要先合并起来,否则边过多。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <queue>
     5 using namespace std;
     6 #define N 1010
     7 #define INF 0x3f3f3f3f
     8 typedef long long LL;
     9 struct Edge {
    10     int u, v; LL cap; int nxt;
    11 } edge[N*N*4];
    12 int cur[N], gap[N], dis[N], pre[N], tot, head[N], S, T;
    13 LL mp[N][N], e[N];
    14 
    15 void Add(int u, int v, LL cap) {
    16     edge[tot] = (Edge) {u, v, cap, head[u]}; head[u] = tot++;
    17     edge[tot] = (Edge) {v, u, 0, head[v]}; head[v] = tot++;
    18 }
    19 
    20 int BFS() {
    21     queue<int> que;
    22     que.push(T);
    23     memset(dis, INF, sizeof(dis));
    24     memset(gap, 0, sizeof(gap));
    25     dis[T] = 0;  gap[0]++;
    26     while(!que.empty()) {
    27         int u = que.front(); que.pop();
    28         for(int i = head[u]; ~i; i = edge[i].nxt) {
    29             if(dis[edge[i].v] == INF) {
    30                 dis[edge[i].v] = dis[u] + 1;
    31                 gap[dis[edge[i].v]]++;
    32                 que.push(edge[i].v);
    33             }
    34         }
    35     }
    36 }
    37 
    38 LL ISAP(int n) {
    39     BFS();
    40     memcpy(cur, head, sizeof(cur));
    41     LL ans = 0, flow;
    42     int i, u = pre[S] = S, index;
    43     while(dis[S] < n) {
    44         if(u == T) {
    45             flow = 100000000000000000;
    46             for(i = S; i != T; i = edge[cur[i]].v)
    47                 if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i;
    48             for(i = S; i != T; i = edge[cur[i]].v)
    49                 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow;
    50             ans += flow; u = index;
    51         }
    52         for(i = cur[u]; ~i; i = edge[i].nxt) if(dis[edge[i].v] == dis[u] - 1 && edge[i].cap) break;
    53         if(~i) { cur[u] = i; pre[edge[i].v] = u; u = edge[i].v; }
    54         else {
    55             int md = n + 1;
    56             if(--gap[dis[u]] == 0) break;
    57             for(i = head[u]; ~i; i = edge[i].nxt)
    58                 if(md > dis[edge[i].v] && edge[i].cap) md = dis[edge[i].v], cur[u] = i;
    59             gap[dis[u] = md + 1]++;
    60             u = pre[u];
    61         }
    62     }
    63     return ans;
    64 }
    65 
    66 int main() {
    67     int n; LL w, sum = 0;
    68     scanf("%d", &n);
    69     S = 0; T = n + 1;
    70     memset(head, -1, sizeof(head)); tot = 0;
    71     for(int i = 1; i <= n; i++)
    72         scanf("%lld", &w), Add(S, i, w);
    73     for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%lld", &mp[i][j]), e[i] += mp[i][j], sum += mp[i][j];
    74     for(int i = 1; i <= n; i++) {
    75         Add(i, T, e[i]);
    76         for(int j = i + 1; j <= n; j++) {
    77             Add(i, j, mp[i][j] * 2); Add(j, i, mp[i][j] * 2);
    78         }
    79     }
    80     LL ans = ISAP(T + 1);
    81     printf("%lld
    ", sum - ans);
    82     return 0;
    83 }
  • 相关阅读:
    shell的执行顺序问题
    七层负载均衡——HAProxy
    不要自以为是码农
    SSL协议运行机制
    Linux启动流程
    MIM协议与Base64编码
    Adele的生活
    你值得拥有:25个Linux性能监控工具
    [Zabbix] 如何实现邮件报警通知以及免费短信报警通知
    php.ini中date.timezone设置分析
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6412581.html
Copyright © 2020-2023  润新知