zoukankan      html  css  js  c++  java
  • 【HDU 6126】Give out candies 最小割

    题意

    有$n​$个小朋友,给每个人分$1~m​$个糖果,有k个限制 限制形如$(x,y,z)​$ 表示第$x​$个人分到的糖数减去第$y​$个人分到的糖数不大于$z​$,给第$i​$个人$j​$颗糖获得的满意度为$w_{i,j}​$,问总满意度最大值


    点$(i,j)$表示第$i$个人分$j$个糖,当这个点属于$s$集合成立,因为是求满意度最大值,所以负权建边,同时加上个最大值$Max$使得满足最大流模板,假设不考虑限制,对于每一个$i$,连边$(i,j) ightarrow (i,j+1),jin[1,m)$,边权为$Max-w_i,j$,$s ightarrow(i,1)$,那么此时的最小割便是能得到最大满意度

    对于每个限制,当$x$选了$i$个糖,那么$y$至少要选$i-z$个糖,连边$(x,i) ightarrow s, i in [1,m] land i - z < 1$,或$(x,i) ightarrow (y,i-z), i land [1,m] land 1 le i - z le m$ ,或$(x,i) ightarrow t, i in [1,m] land i - z > m$ ,边权为$inf$,这样,当不满足限制的割边发生时,得到的最小割会大于$inf$

    关于限制的建边的详细题解:http://blog.csdn.net/wing_wuchen/article/details/77407413

    答案为$Max*n-mincut$

    代码

    #include <bits/stdc++.h>
    #define MAXN 300005
    #define MAXM 50000005
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long LL;
    struct Edge {
        int to, nxt, c;
    }edge[MAXM];
    int head[MAXN], cnt = 0;
    int d[MAXN], cur[MAXN], pre[MAXN], gap[MAXN];
    int source, sink, limit;
    void init() {
        memset(head, -1, sizeof(head));
        cnt = 0;
    }
    inline void add_edge(int u, int v, int c) {
        edge[cnt].to = v;
        edge[cnt].nxt = head[u];
        edge[cnt].c = c;
        head[u] = cnt++;
    }
    
    inline void add(int u, int v, int c) {
        add_edge(u, v, c); add_edge(v, u, 0);
    }
    
    void rev_bfs() {
        memset(gap, 0, sizeof(gap));
        memset(d, -1, sizeof(d));
        d[sink] = 0;
        gap[0] = 1;
        queue<int> que;
        que.push(sink);
        while(!que.empty()) {
            int u = que.front(); que.pop();
            for(int i = head[u]; ~i; i = edge[i].nxt) {
                int v = edge[i].to;
                if(~d[v])continue;
                d[v] = d[u] + 1;
                gap[d[v]]++;
                que.push(v);
            }
        }
    }
    int isap() {
        memcpy(cur, head, sizeof(cur));
        rev_bfs();
        int flow = 0, i;
        int u = source;
        pre[source] = source;
        while(d[sink] < limit) {
            if(u == sink) {
                int f = inf, neck;
                for(i = source; i != sink; i = edge[cur[i]].to) {
                    if(f > edge[cur[i]].c) {
                        f = edge[cur[i]].c;
                        neck = i;
                    }
                }
                for(i = source; i != sink; i = edge[cur[i]].to) {
                    edge[cur[i]].c -= f;
                    edge[cur[i] ^ 1].c += f;
                }
                flow += f;
                u = neck;
            }
            for(i = cur[u]; ~i; i = edge[i].nxt) {
                if(d[edge[i].to] + 1 == d[u] && edge[i].c) break;
            }
            if(~i) {
                cur[u] = i;
                pre[edge[i].to] = u;
                u = edge[i].to;
            }else {
                if((--gap[d[u]]) == 0) break;
                int mind = limit;
                for(int i = head[u]; ~i; i = edge[i].nxt) {
                    if(edge[i].c && mind > d[edge[i].to]) {
                        cur[u] = i;
                        mind = d[edge[i].to];
                    }
                }
                d[u] = mind + 1;
                gap[d[u]]++;
                u = pre[u];
            }
        }
        return flow;
    }
    int t, n, m, k, w[100][100], x, y, z;
    int get(int x, int y) {return (x - 1) * m + y;}
    int main() {
        scanf("%d", &t);
        while(t--) {
            init();
            scanf("%d%d%d", &n, &m, &k);
            source = 0; sink = n * m + 1; limit = sink + 1;
            for(int i = 1; i <= n; ++i) {
                add(source, get(i, 1), inf);
                for(int j = 1; j <= m; ++j) {
                    scanf("%d", &w[i][j]);
                    if(j < m) add(get(i, j), get(i, j + 1), 1000 - w[i][j]);
                    else add(get(i, j), sink, 1000 - w[i][j]);
                }
            }
            for(int i = 1; i <= k; ++i) {
                scanf("%d%d%d", &x, &y, &z);
                for(int j = 1; j <= m; ++j) {
                    if(j - z < 1) add(get(x, j), source, inf);
                    else if(j - z <= m) add(get(x, j), get(y, j - z), inf);
                    else add(get(x, j), sink, inf);
                }
            }
            int ans = isap();
            if(ans >= inf) printf("-1
    "); else printf("%d
    ", 1000 * n - ans);
        }
        return 0;
    }
    

  • 相关阅读:
    05_python_字典
    04_python_列表
    03_python_基本数据类型
    02_python_while循环/格式化输出/逻辑运算
    01_python_初始python
    vue中v-model的数据双向绑定(重要)
    vue中轮播图的实现
    侦听器watch 监听单个属性
    vue computed监听多个属性
    vue中ajax应用
  • 原文地址:https://www.cnblogs.com/ogiso-setsuna/p/8400622.html
Copyright © 2011-2022 走看看