简体   繁体   English

动态编程:USACO最佳挤奶

[英]Dynamic Programming: USACO Optimal Milking

I have been looking at some USACO gold level algorithm problems, and I need someone to help explain the solution of this problem to me. 我一直在寻找一些USACO黄金级算法问题,并且需要有人帮助我向我解释该问题的解决方案。 Here is the problem, and the solution is below: 是问题所在,解决方案如下:

Usually the first step in solving incremental-update problems is to solve the problem without the incremental updates, but in this case it can lead one up a blind alley. 通常,解决增量更新问题的第一步是在不进行增量更新的情况下解决问题,但是在这种情况下,它可能导致一个盲目的小巷。 There is a quite simple DP solution to the non-incremental version of this problem, but it is not at all obvious how to incrementally update this in less than linear time. 对于此问题的非增量版本,有一个非常简单的DP解决方案,但是如何在少于线性时间的时间内增量更新该问题一点也不明显。

Instead, we can find a divide-and-conquer DP solution that will be easier to update. 相反,我们可以找到一种分治法的DP解决方案,该解决方案将更易于更新。 Divide the range in half, and in each half solve the problem again. 将范围分成两半,每半再一次解决问题。 In fact, we solve four variants of the problem, depending on whether the left and/or right endpoint is allowed to be used. 实际上,根据是否允许使用左端点和/或右端点,我们解决了该问题的四个变体。 Given these results from the two halves, we can easily combine them to form the results for the whole range. 给定这两个部分的结果,我们可以轻松地将它们组合起来以形成整个范围的结果。 The ranges form a segment tree over the barn, where each tree node depends on its two children, and the answer is held at the root of the tree. 范围在谷仓上形成了一个段树,每个树节点都取决于它的两个子节点,答案位于树的根部。

Given this tree structure, it is now clear how we can make incremental updates in O(log N) time: an update affects a leaf of the tree, which in turn requires its O(log N) ancestors to be updated. 有了这种树结构,现在很清楚我们如何在O(log N)时间内进行增量更新:更新会影响树的叶子,这又需要更新其O(log N)祖先。

There is no code in this solution, and I don't really understand how to implement this idea. 该解决方案中没有代码,而且我不太了解如何实现该想法。 I would really appreciate it if someone could explain it more thoroughly or show me how to code it. 如果有人可以更详尽地解释它或向我展示如何编写代码,我将不胜感激。

Edit: 编辑:

I understand what the solution is saying better now, and I have coded a solution. 我了解该解决方案现在说的更好,并且已经编写了一个解决方案。 However, the code only works for the first two test data. 但是,该代码仅适用于前两个测试数据。 I thought I programmed what they had said, but I must have made an error. 我以为我对他们说的话进行了编程,但是我一定犯了一个错误。 Here is my code (in Java): 这是我的代码(使用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;
        }
    }
}

Which part you don't understand? 您不了解哪一部分?

First paragraph says that there is an easy solution when there are no updates (ie if the farmer does not do maintenance, same amount of milk is extracted everyday. This amount can be calculated using DP). 第一段说,如果没有更新,则有一个简单的解决方案(即,如果农民不进行维护,则每天提取相同量的牛奶。该数量可以使用DP计算)。

Second paragraph says that there is a divide and conquer solution which is easier to update when capacity of machines change. 第二段说有一个分而治之的解决方案,当机器容量变化时,更容易更新。 It also provides the outline of solution. 它还提供了解决方案的概述。

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

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