zoukankan      html  css  js  c++  java
  • Solution 「ZJOI 2013」「洛谷 P3337」防守战线

    \(\mathcal{Description}\)

      Link.

      有 \(n\) 个位置,从左至右编号 \(1\sim n\)。在第 \(i\) 个位置放一座塔的代价为 \(c_i\),一个位置可以放任意数量的塔。给定 \(m\) 个要求,第 \(i\) 个表示 \([l_i,r_i]\) 内至少有 \(d_i\) 座塔。求最小的代价和。

      \(n\le10^3\),其余参数 \(\le10^4\)

    \(\mathcal{Solution}\)

      经历了逝量的 whk 学习,我学会了背套路。(

      原问题可以写成线规:

    \[\begin{aligned} \min~~~~&z=\sum_{i=1}^nc_i(x_i-x_{i-1})\\ \text{s.t.}~~~~&x_i\ge x_{i-1}\\ &x_{r_i}-x_{l_i-1}\ge d_i \end{aligned}, \]

    而它显然等价于:

    \[\begin{aligned} \min~~~~z'=\sum_{i=1}^n(c_i-c_{i+1})x_i+\sum_{i=1}^nI\max\{x_{i-1}-x_i,0\}+\sum_{i=1}^mI\max\{d_i-x_{r_i}+x_{l_i-1},0\} \end{aligned}. \]

    ​其中 \(I\) 是一个足够大的常数。

      我们的论文套路是,对于以下线规:

    \[\min~~~~z=\sum_ub_ux_u+\sum_{\lang u,v\rang}c_{uv}\max\{0,x_v-x_u-w_{uv}\}, \]

    其对应最小费用流模型:

    • \(b_u\) 表示 \(u\) 点的流出量-流入量。

      为了流量守恒,对于 \(b_u>0\)\(u\),连 \(\lang S,u,b_u,0\rang\)

      对于 \(b_u<0\)\(u\),连 \(\lang u,T,-b_u,0\rang\)

    • \(c_{uv}\) 表示 \(\lang u,v\rang\) 的容量,\(w_{uv}\) 表示 \(\lang u,v\rang\) 的费用,所以连边 \(\lang u,v,c_{uv},w_{uv}\rang\)

    该图的最小费用最大流的费用的相反数就是答案。

      点的系数出减入,max 外是容量,max 内是费用,减数连向被减数,最小费用相反数!


      但 whk 是落后的,我们来证明。令 \(f_{uv}\) 表示 \(\lang u,v\rang\) 的流量,考虑在上述条件下的最小费用流形式:

    \[\begin{aligned} \min~~~~&z=\sum_{\lang u,v\rang}c_{uv}f_{uv}\\ \text{s.t.}~~~~&-f_{uv}\ge-c_{uv}\\ &\sum_v f_{vu}-\sum_vf_{uv}=-b_u \end{aligned}. \]

    \(p_{uv}\) 表示第一类限制的对偶,\(q_u\) 表示第二类限制的对偶,得到:

    \[\begin{aligned} \max~~~~&z=\sum_u -b_uq_u+\sum_{\lang u,v\rang}-c_{uv}p_{uv}\\ \text{s.t.}~~~~&q_v-q_u-p_{uv}\le w_{uv} \end{aligned}. \]

    那么这个 \(p_{uv}\) 非常的自由,直接给它定成最优,所以

    \[\min~~~~z=\sum_ub_uq_u+\sum_{\lang u,v\rang}c_{uv}\max\{0,q_v-q_u-w_{uv}\} \]

    的相反数就是答案。 \(\square\)

    \(\mathcal{Code}\)

      总之得写势能 Dijkstra。

    /*+Rainybunny+*/
    
    #include <bits/stdc++.h>
    
    #define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
    #define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
    
    typedef std::pair<int, int> PII;
    #define fi first
    #define se second
    
    const int MAXN = 1e3, MAXM = 1e4, IINF = 0x3f3f3f3f;
    int n, m, c[MAXN + 5], l[MAXM + 5], r[MAXM + 5], d[MAXM + 5];
    
    namespace FlowGraph {
    
    const int MAXND = MAXN + 3, MAXEG = MAXN * 2 + MAXM;
    int ecnt = 1, S, T, head[MAXND + 5], curh[MAXND + 5];
    int hig[MAXND + 5], dis[MAXND + 5];
    bool instk[MAXND + 5];
    struct Edge { int to, flw, cst, nxt; } graph[MAXEG * 2 + 5];
    
    inline void link(const int s, const int t, const int f, const int c) {
        graph[++ecnt] = { t, f, c, head[s] }, head[s] = ecnt;
        graph[++ecnt] = { s, 0, -c, head[t] }, head[t] = ecnt;
    }
    
    inline bool spfa() {
        static bool inq[MAXND + 5]; static std::queue<int> que;
        rep (i, 0, T) dis[i] = IINF;
        dis[S] = 0, que.push(S);
        while (!que.empty()) {
            int u = que.front(); que.pop(), inq[u] = false;
            for (int i = head[u], v; i; i = graph[i].nxt) {
                if (graph[i].flw && dis[u] + graph[i].cst < dis[v = graph[i].to]) {
                    dis[v] = dis[u] + graph[i].cst;
                    if (!inq[v]) inq[v] = true, que.push(v);
                }
            }
        }
        return dis[T] != IINF;
    }
    inline bool dijkstra() {
        static std::priority_queue<PII, std::vector<PII>, std::greater<PII> > heap;
        rep (i, 0, T) hig[i] += dis[i], dis[i] = IINF;
        heap.push({ dis[S] = 0, S });
        while (!heap.empty()) {
            PII p(heap.top()); heap.pop();
            if (dis[p.se] != p.fi) continue;
            for (int i = head[p.se], v; i; i = graph[i].nxt) {
                int d = p.fi + graph[i].cst + hig[p.se] - hig[v = graph[i].to];
                if (graph[i].flw && dis[v] > d) heap.push({ dis[v] = d, v });
            }
        }
        return dis[T] != IINF;
    }
    
    inline PII augment(const int u, int iflw) {
        if (u == T) return { iflw, 0 };
        PII ret(0, 0); instk[u] = true;
        for (int &i = curh[u], v; i; i = graph[i].nxt) {
            if (graph[i].flw && !instk[v = graph[i].to]
              && dis[v] == dis[u] + hig[u] - hig[v] + graph[i].cst) {
                PII tmp(augment(v, std::min(iflw, graph[i].flw)));
                ret.fi += tmp.fi, ret.se += graph[i].cst * tmp.fi + tmp.se;
                iflw -= tmp.fi, graph[i].flw -= tmp.fi, graph[i ^ 1].flw += tmp.fi;
                if (!iflw) break;
            }
        }
        if (ret.fi) instk[u] = false;
        return ret;
    }
    
    inline PII dinic() {
        PII ret(0, 0);
        for (spfa(); dijkstra(); ) {
            rep (i, 0, T) curh[i] = head[i], instk[i] = false;
            PII tmp(augment(S, IINF));
            ret.fi += tmp.fi, ret.se += tmp.se;
        }
        return ret;
    }
    
    } using namespace FlowGraph;
    
    int main() {
        scanf("%d %d", &n, &m);
        rep (i, 1, n) scanf("%d", &c[i]);
        rep (i, 1, m) scanf("%d %d %d", &l[i], &r[i], &d[i]);
    
        S = n + 1, T = n + 2;
        rep (i, 0, n) {
            if (c[i] > c[i + 1]) link(S, i, c[i] - c[i + 1], 0);
            else link(i, T, c[i + 1] - c[i], 0);
        }
        rep (i, 0, n - 1) link(i + 1, i, IINF, 0);
        rep (i, 1, m) link(r[i], l[i] - 1, IINF, -d[i]);
    
        printf("%d\n", -dinic().se);
        return 0;
    }
    
    
  • 相关阅读:
    构建安全的Xml Web Service系列之如何察看SoapMessage
    web2.0盈利模式
    Asp.Net ajax v1.0莫名出现"Sys未定义"的原因
    北京街头发生一幕~让人深思!!!
    算法函数:得到一个字符串中的最大长度的数字
    手把手教你如何扩展GridView之自动排序篇
    手把手教你如何扩展GridView之自带Excel和Word导出
    nhibernate学习之集合组合依赖
    递归算法学习系列一(分而治之策略)
    手把手教你如何扩展GridView之自带分页
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15700263.html
Copyright © 2011-2022 走看看