繁体   English   中英

动态编程:USACO最佳挤奶

[英]Dynamic Programming: USACO Optimal Milking

我一直在寻找一些USACO黄金级算法问题,并且需要有人帮助我向我解释该问题的解决方案。 是问题所在,解决方案如下:

通常,解决增量更新问题的第一步是在不进行增量更新的情况下解决问题,但是在这种情况下,它可能导致一个盲目的小巷。 对于此问题的非增量版本,有一个非常简单的DP解决方案,但是如何在少于线性时间的时间内增量更新该问题一点也不明显。

相反,我们可以找到一种分治法的DP解决方案,该解决方案将更易于更新。 将范围分成两半,每半再一次解决问题。 实际上,根据是否允许使用左端点和/或右端点,我们解决了该问题的四个变体。 给定这两个部分的结果,我们可以轻松地将它们组合起来以形成整个范围的结果。 范围在谷仓上形成了一个段树,每个树节点都取决于它的两个子节点,答案位于树的根部。

有了这种树结构,现在很清楚我们如何在O(log N)时间内进行增量更新:更新会影响树的叶子,这又需要更新其O(log N)祖先。

该解决方案中没有代码,而且我不太了解如何实现该想法。 如果有人可以更详尽地解释它或向我展示如何编写代码,我将不胜感激。

编辑:

我了解该解决方案现在说的更好,并且已经编写了一个解决方案。 但是,该代码仅适用于前两个测试数据。 我以为我对他们说的话进行了编程,但是我一定犯了一个错误。 这是我的代码(使用Java):

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Scanner;

/**
 * Created by jameslennon on 1/19/14.
 */
public class optmilk {
    static int n, d;
    static int[] m, indx;
    static node[] tree;

    public static void main(String[] args) throws Exception {
        Scanner in = new Scanner(new File("optmilk.in"));
        PrintWriter out = new PrintWriter(new FileWriter("optmilk.out"));
        n = in.nextInt();
        m = new int[n];
        indx = new int[n];
        d = in.nextInt();
        tree = new node[1 << n + 1];
        for (int i = 0; i < n; i++) {
            m[i] = in.nextInt();
        }
        construct(1, 0, n - 1);
        int r = 0;
        for (int i = 0; i < d; i++) {
            int a = in.nextInt() - 1, b = in.nextInt();
            update(a, b);
            m[a] = b;
            r += max(tree[1].none, tree[1].both, tree[1].left, tree[1].right);
        }
        //System.out.println(r);
        out.println(r);
        out.close();
        System.exit(0);
    }

    private static void update(int a, int b) {
        int i = indx[a];
        int w = 1;
        tree[i].both = b;
        i /= 2;
        while (true) {
            update_node(i, w);
            w *= 2;
            if (i == 1) break;
            i /= 2;
        }
    }

    private static int max(int... a) {
        int max = Integer.MIN_VALUE;
        for (int b : a) {
            max = Math.max(max, b);
        }
        return max;
    }

    private static void update_node(int i, int w) {
        if (w == 1) {
            tree[i].left = tree[2 * i].both;
            tree[i].right = tree[2 * i + 1].both;
        } else {
            tree[i].none = max(tree[2 * i].none + tree[2 * i + 1].none, tree[2 * i].right + tree[2 * i + 1].none, tree[2 * i].none + tree[2 * i + 1].left);
            tree[i].right = max(tree[2 * i].none + tree[2 * i + 1].right, tree[2 * i].right + tree[2 * i + 1].right, tree[2 * i].none + tree[2 * i + 1].both);
            tree[i].left = max(tree[2 * i].left + tree[2 * i + 1].none, tree[2 * i].both + tree[2 * i + 1].none, tree[2 * i].left + tree[2 * i + 1].left);
            tree[i].both = max(tree[2 * i].left + tree[2 * i + 1].right, tree[2 * i].both + tree[2 * i + 1].right, tree[2 * i].left + tree[2 * i + 1].both);
        }
    }

    private static void construct(int i, int a, int b) {
        if (b - a == 0) {
            indx[a] = i;
            tree[i] = new node(0, 0, 0, m[a]);
            return;
        }
        construct(2 * i, a, (a + b) / 2);
        construct(2 * i + 1, (a + b) / 2 + 1, b);
        int both = max(tree[2 * i].left + tree[2 * i + 1].right, tree[2 * i].both + tree[2 * i + 1].right, tree[2 * i].left + tree[2 * i + 1].both);
        if (b - a == 1) both = 0;
        tree[i] = new node(max(tree[2 * i].none + tree[2 * i + 1].none, tree[2 * i].right + tree[2 * i + 1].none, tree[2 * i].none + tree[2 * i + 1].left),
                max(tree[2 * i].none + tree[2 * i + 1].right, tree[2 * i].right + tree[2 * i + 1].right, tree[2 * i].none + tree[2 * i + 1].both),
                max(tree[2 * i].left + tree[2 * i + 1].none, tree[2 * i].both + tree[2 * i + 1].none, tree[2 * i].left + tree[2 * i + 1].left),
                both);
    }

    static class node {
        int none, right, left, both;

        public node(int n, int r, int l, int b) {
            none = n;
            right = r;
            left = l;
            both = b;
        }
    }
}

您不了解哪一部分?

第一段说,如果没有更新,则有一个简单的解决方案(即,如果农民不进行维护,则每天提取相同量的牛奶。该数量可以使用DP计算)。

第二段说有一个分而治之的解决方案,当机器容量变化时,更容易更新。 它还提供了解决方案的概述。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM