zoukankan      html  css  js  c++  java
  • CF704D Captain America(上下界网络流)

    传送门

    题意:
    二维平面给出(n)个点,现在可以给每个点进行染色,染红色的代价为(r),染蓝色的代价为(b)
    之后会有(m)个限制,形式如:(t_i l_i d_i),当(t_i=1)时,表示(l_i)行两种颜色的点数相差不超过(d_i);类似地,当(t_i=2)时表示的是列时的状态。
    问最终怎么染色代价最小且符合限制条件。

    思路:

    • 带上下界的网络流。
    • 我们不妨设(r<b),那么肯定是红点越多越好。我们找准最大这个数量关系,然后考虑最大流。
    • 建图方式为:左右两排分别表示行和列,中间则为每个点,源点和左排相连带有上下界,汇点和右排相连带有上下界。
    • 上下界很好推,假设第(i)行共(tot_i)个点,我们选(x)个红点,那么就有:(|x-(tot - x)|leq d),绝对值打开化简即可得到(x)的范围,若一个满足范围,另一个点也必然满足范围。
    • 为什么要在两排中间加上点?因为我们最后要输出方案,我们需要根据流过点的流量来判断这个点是否染色。

    这种有源有汇最大流,首先转化为无源无汇最大流,得到(s)(t)的可行流,最后去掉附加点和边,最后再从(s)(t)跑一次最大流,两次的答案加起来即可得到答案。
    注意进入流量若大于出度流量,我们连接源点向它来补充这多出来的。
    详见代码:

    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5e5 + 5;
    
    #define INF 0x3f3f3f3f
    int s, t, SS, TT;
    int n, m, r, b, f;
    void Fail() {
        cout << -1 << '
    ';
        exit(0);
    }
    template <class T>
    struct Dinic{
        struct Edge{
            int v, next;
            T flow;
            Edge(){}
            Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
        }e[N << 1];
        int head[N], tot;
        int dep[N], M[N];
        int all;
        void init() {
            memset(head, -1, sizeof(head)); tot = 0;
        }
        void adde(int u, int v, T down, T up) {
            if(up < down) Fail();
            e[tot] = Edge(v, head[u], up - down);
            head[u] = tot++;
            e[tot] = Edge(u, head[v], 0);
            head[v] = tot++;
            M[u] -= down; M[v] += down;
        }
        void adde() {
            for(int i = 0; i <= t; i++) {
                if(M[i] > 0) adde(SS, i, 0, M[i]);
                else if(M[i] < 0) adde(i, TT, 0, -M[i]);
            }
            adde(t, s, 0, INF);
        }
        bool BFS(int _S, int _T) {
            memset(dep, 0, sizeof(dep));
            queue <int> q; q.push(_S); dep[_S] = 1;
            while(!q.empty()) {
                int u = q.front(); q.pop();
                for(int i = head[u]; ~i; i = e[i].next) {
                    int v = e[i].v;
                    if(!dep[v] && e[i].flow > 0) {
                        dep[v] = dep[u] + 1;
                        q.push(v);
                    }
                }
            }
            return dep[_T] != 0;
        }
        T dfs(int _S, int _T, T a) {
            T flow = 0, f;
            if(_S == _T || a == 0) return a;
            for(int i = head[_S]; ~i; i = e[i].next) {
                int v = e[i].v;
                if(dep[v] != dep[_S] + 1) continue;
                f = dfs(v, _T, min(a, e[i].flow));
                if(f) {
                    e[i].flow -= f;
                    e[i ^ 1].flow += f;
                    flow += f;
                    a -= f;
                    if(a == 0) break;
                }
            }
            if(!flow) dep[_S] = -1;
            return flow;
        }
        T dinic(int _S, int _T) {
            T max_flow = 0;
            while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
            return max_flow;
        }
        T work() {
            int tmp = dinic(SS, TT);
            for(int i = head[SS]; i != -1; i = e[i].next) {
                if(e[i].flow) Fail();
            }
            int ans = e[tot - 1].flow;
            e[tot - 1].flow = e[tot - 2].flow = 0;
            for(int i = head[SS]; i != -1; i = e[i].next) {
                e[i].flow = e[i ^ 1].flow = 0;
            }
            for(int i = head[TT]; i != -1; i = e[i].next) {
                e[i].flow = e[i ^ 1].flow = 0;
            }
            ans += dinic(s, t);
            return ans;
        }
        //f = 1 -> r > b;
        void Print(int f, int L, int R) {
            for(int i = L + 1; i <= L + n; i++) {
                bool flag = false;
                for(int j = head[i]; j != -1; j = e[j].next) {
                    int v = e[j].v;
                    if(e[j].flow == 0 && v > n + L && v <= n + L + R) {
                        flag = true;
                        cout << (f == 1 ? 'b' : 'r');
                    }
                }
                if(!flag) cout << (f == 1 ? 'r' : 'b');
            }
        }
    };
    Dinic <int> solver;
    int x[N], y[N], X[N], Y[N];
    int mxx[N], mxy[N], cntx[N], cnty[N];
    void Hash(int *a, int *b, int &c) {
        sort(b + 1, b + n + 1);
        c = unique(b + 1, b + n + 1) - b - 1;
        for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + c + 1, a[i]) - b;
    }
    void Hash(int &a, int &b) {
        Hash(x, X, a); Hash(y, Y, b);
    }
    void run() {
        cin >> r >> b;
        if(r >= b) {
            f = 1;
            swap(r, b);
        }
        solver.init();
        for(int i = 1; i <= n; i++) {
            cin >> x[i] >> y[i];
            X[i] = x[i], Y[i] = y[i];
        }
        int lx, ly;
        Hash(lx, ly);
        dbg(lx, ly);
        s = 0, t = lx + ly + n + 1;
        SS = t + 1, TT = t + 2;
        for(int i = 1; i <= n; i++) {
            solver.adde(x[i], lx + i, 0, 1);
            solver.adde(lx + i, y[i] + n + lx, 0, 1);
        }
        for(int i = 1; i <= lx; i++) mxx[i] = n;
        for(int i = 1; i <= ly; i++) mxy[i] = n;
        for(int i = 1; i <= m; i++) {
            int t, l, d; cin >> t >> l >> d;
            if(t & 1) {
                int p = lower_bound(X + 1, X + lx + 1, l) - X;
                if(X[p] != l) continue;
                else mxx[p] = min(mxx[p], d);
            }
            else {
                int p = lower_bound(Y + 1, Y + ly + 1, l) - Y;
                if(Y[p] != l) continue;
                else mxy[p] = min(mxy[p], d);
            }
        }
        for(int i = 1; i <= n; i++) ++cntx[x[i]];
        for(int i = 1; i <= n; i++) ++cnty[y[i]];
        for(int i = 1; i <= lx; i++) {
            if(cntx[i] <= mxx[i]) solver.adde(s, i, 0, INF);
            else solver.adde(s, i, (cntx[i] - mxx[i] + 1) / 2, (cntx[i] + mxx[i]) / 2);
        }
        for(int i = 1; i <= ly; i++) {
            if(cnty[i] <= mxy[i]) solver.adde(n + lx + i, t, 0, INF);
            else solver.adde(n + lx + i, t, (cnty[i] - mxy[i] + 1) / 2, (cnty[i] + mxy[i]) / 2);
        }
        solver.adde();
        int flow = solver.work();
        cout << 1ll * flow * r + 1ll * (n - flow) * b << '
    ';
        solver.Print(f, lx, ly);
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n >> m) run();
        return 0;
    }
    
    
  • 相关阅读:
    uva 11078
    hdu1520(树状dp)
    从Markov Process到Markov Decision Process
    剑指Offer系列编程题详解全集
    L1正则和L2正则的区别详解
    协方差详解
    牛顿法和梯度下降法的比较
    C++ const各种用法总结
    Exploration and Exploitation
    RL Algorithm Components
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11729290.html
Copyright © 2011-2022 走看看