[英]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.