簡體   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