• 「雅礼集训 2017」价


    传送门

    一个不太显然的最小割做法。。。

    我们这么连边:源点向药物连 (+ infty - p_i) 容量的边,药物向它对应的药材连 (+ infty) 容量的边,药材向汇点连 (+ infty) 容量的边。

    用源点的流量减去最小割,再负回来就可以求出答案了。

    怎么理解呢?割掉一条边表示不选其对应的药物或药材,我们发现最后的方案一定是完美匹配,也就是说我们肯定会让药物对应的药材出现重复,然后我们肯定不想割掉更多的边,也就是说只需求出最小割就好了。

    参考代码:

    #include <cstring>
    #include <cstdio>
    
    int min(int a, int b) { return a < b ? a : b; }
    template < class T > void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
    
    const int _ = 1e5 + 5, __ = 2e6 + 5, INF = 2147483547, top = 1e7;
    
    int tot = 1, head[_]; struct Edge { int v, w, nxt; } edge[__ << 1];
    void Add_edge(int u, int v, int w) { edge[++tot] = (Edge) { v, w, head[u] }, head[u] = tot; }
    void Link(int u, int v, int w) { Add_edge(u, v, w), Add_edge(v, u, 0); }
    
    int n, ans, s, t, dep[_], cur[_];
    
    int bfs() {
        static int hd, tl, Q[_]; hd = tl = 0;
        memset(dep, 0, sizeof (int) * (t - s + 1));
        dep[s] = 1, Q[++tl] = s;
        while (hd < tl) {
            int u = Q[++hd];
            for (int i = head[u]; i; i = edge[i].nxt) {
                int v = edge[i].v, w = edge[i].w;
                if (dep[v] == 0 && w > 0)
                    dep[v] = dep[u] + 1, Q[++tl] = v;
            }
        }
        return dep[t] != 0;
    }
    
    int dfs(int u, int flow) {
        if (u == t) return flow;
        for (int& i = cur[u]; i; i = edge[i].nxt) {
            int v = edge[i].v, w = edge[i].w;
            if (dep[v] == dep[u] + 1 && w > 0) {
                int res = dfs(v, min(flow, w));
                if (res) { edge[i].w -= res, edge[i ^ 1].w += res; return res; }
            }
        }
        return 0;
    }
    
    int Dinic() {
        int res = 0;
        while (bfs()) {
            memcpy(cur, head, sizeof head);
            while (int d = dfs(s, INF)) res += d;
        }
        return res;
    }
    
    int main() {
        read(n), s = 0, t = n << 1 | 1;
        for (int x, y, i = 1; i <= n; ++i) {
            read(x); while (x--) read(y), Link(i, y + n, INF);
        }
        for (int x, i = 1; i <= n; ++i)
            read(x), ans += top - x, Link(s, i, top - x), Link(i + n, t, top);
        printf("%d
    ", Dinic() - ans);
        return 0;
    }
    
  • 相关阅读:
    js去除空格
    Quartz定时任务学习(九)Quartz监听器
    Quartz定时任务学习(七)Cron 触发器
    数据挖掘之聚类算法K-Means总结
    SQL SERVER分区具体例子详解
    基于basys2驱动LCDQC12864B的verilog设计图片显示
    图像处理的多线程计算
    三维空间中的几种坐标系
    2017年要学习的三个CSS新特性
    Mesos 资源分配
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/13096382.html
Copyright © 2020-2023  润新知