动态编程达到阈值?

时间:2017-10-27 19:24:29

标签: algorithm dynamic-programming

假设您正在使用弹性笔记本电脑。我们还假设您的液压机具有功率i,设置m(最大功率)可以打破笔记本电脑。如果笔记本电脑在电源i处断电,那么它也会因im而中断。如果它没有在权力i处中断,则0i的任何内容都不会中断。

我认为最好的方法是尽量减少我们需要使用印刷机的次数,以便找出i是什么,是分成两半并继续重复。如果没有破坏则走高,如果破裂则走低。我认为这是O(n/2)的复杂性,是吗?

现在说我们只有n笔记本电脑可用,如果所有n在我们达到阈值之前中断,那么我们就失败了。如果我们有n台笔记本电脑并且印刷机设置了m,我将如何获得动态编程算法,以便我们能够在最坏的情况下获得印刷机运行的最少次数?

我是否可以使用非限制方式的答案?子问题是什么?

2 个答案:

答案 0 :(得分:1)

这不是答案,但评论时间太长了。

  • 如果您只有一台笔记本电脑,那么线性搜索整个范围就不会做得更好,这会产生O(m)复杂度。

  • 使用2台笔记本电脑,您可以做得更好。

    首先尝试sqrt(2m)。如果笔记本电脑坏了,您需要sqrt(2m) - 1尝试第二个。如果没有,请使用2*sqrt(2m) - 1处的第一个。通常,只要第一台笔记本电脑保持不变,请选择p(k+1)设置为p(k) + sqrt(2m) - k。这可以保证,如果它中断,你仍然会sqrt(2m) - k尝试检查未知的范围,并在完成sqrt(2m)次尝试时完成工作,无论它在哪里发生。

    如果第一台笔记本电脑永远不会中断,您再次m尝试到达sqrt(2m)(我不想做数学,因为SO不支持LaTeX,但它非常简单,试试吧。

    因此,对于2台笔记本电脑,复杂度为O(sqrt(m))

您拥有的笔记本电脑越多,分析就越困难。这个想法仍然存在:选择这样的设置,两个结果都需要相同数量的尝试才能完成。可以证明,只要n远小于log(m),复杂性就是O(m ** (1/n))

答案 1 :(得分:0)

第一个问题确实可以通过首先尝试 m / 2 来解决,并根据结果尝试 m / 4 3m / 4 ,...等。这使问题 O(log(m)),而不是 O(m / 2)(我认为 n 是一个错字)。

第二个版本也称为egg dropping problem

递归函数可以帮助查找尝试次数。为避免重复计算两次相同的配置,您确实可以使用动态编程。并且你有足够的笔记本电脑来执行二进制搜索(取中间压力并取决于结果占据剩余压力的中间,等等),停止递归并返回对数(基数2)(不是一半) !)剩余压力的数量。

以下是基本JavaScript中的实现:



function getLeastAttempts(numPressures, numLaptops) {
    var memo = {}; // Storage for known results (dynamic programming)

    function best(numPressures, numLaptops) {
        var result, numMinAttempts, numAttempts, pressure;
        // If no pressures available, we need no more attempts
        if (numPressures <= 0 || numLaptops <= 0) return { numAttempts: 0 };
        // We ccould apply each pressure from low to high to minimise damage;
        //   this represents an upper limit to the minimum number of attempts we need:
        result = {
            numAttempts: numPressures,
            firstAttemptAtPressure: 1
        };
        // If we cannot to afford losing another laptop without finding out the
        //    answer, then that is what we will have to do: from low to high:
        if (numLaptops == 1) return result;
        // Otherwise check if we have calculated this before
        if (memo[numLaptops] && memo[numLaptops][numPressures])
            return memo[numLaptops][numPressures];
        // Otherwise if we have enough laptops for doing a binary search:
        if (2**numLaptops > numPressures) return {
            numAttempts: Math.floor(Math.log2(numPressures)) + 1,
            firstAttemptAtPressure: Math.floor(numPressures / 2)
        };
        // Otherwise, apply recursion to find out the least number of attempts
        for (pressure = 0; pressure < numPressures; pressure++) {
            // Applying this pressure to the laptop can have 2 results, take the worst
            //    of the two and add one for representing this attempt:
            numAttempts = 1 + Math.max(
                // 1. It breaks the laptop: try lower pressures with one less laptop
                best(pressure, numLaptops-1).numAttempts,
                // 2. The laptop is OK: try higher pressures with same laptops
                best(numPressures - (pressure+1), numLaptops).numAttempts
            );
            // If applying this pressure resulted in fewer attempts to find out the 
            //    truth, then remember this:
            if (numAttempts <= result.numAttempts) {
                result.numAttempts = numAttempts;
                result.firstAttemptAtPressure = pressure;
            }
        }
        // Store result in memory (dynamic programming)
        if (!memo[numLaptops]) memo[numLaptops] = [];
        memo[numLaptops][numPressures] = result;
        // ...and return it
        return result;
    }
    // Outermost call of recursive function
    return best(numPressures, numLaptops);
}

// I/O handling

function processIO() {
    var result = getLeastAttempts(+inpPressures.value, +inpLaptops.value);
    outAttempts.textContent = result.numAttempts;
    outPressure.textContent = result.firstAttemptAtPressure;
}

inpPressures.oninput = processIO;
inpLaptops.oninput = processIO;
processIO(); // invoke calculation on page load
&#13;
Highest pressure (m): <input type="number" id="inpPressures" value=100><br>
Number of laptops (n): <input type="number" id="inpLaptops" value=3><br>
Number of attempts: <span id="outAttempts"></span><br>
First pressure to attempt: <span id="outPressure"></span><br>
&#13;
&#13;
&#13;

将代码段中的输入更改为实验。

此算法不包括Wikipedia article中提到的最终优化。