假设您正在使用弹性笔记本电脑。我们还假设您的液压机具有功率i
,设置m
(最大功率)可以打破笔记本电脑。如果笔记本电脑在电源i
处断电,那么它也会因i
到m
而中断。如果它没有在权力i
处中断,则0
到i
的任何内容都不会中断。
我认为最好的方法是尽量减少我们需要使用印刷机的次数,以便找出i
是什么,是分成两半并继续重复。如果没有破坏则走高,如果破裂则走低。我认为这是O(n/2)
的复杂性,是吗?
现在说我们只有n
笔记本电脑可用,如果所有n
在我们达到阈值之前中断,那么我们就失败了。如果我们有n
台笔记本电脑并且印刷机设置了m
,我将如何获得动态编程算法,以便我们能够在最坏的情况下获得印刷机运行的最少次数?
我是否可以使用非限制方式的答案?子问题是什么?
答案 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;
将代码段中的输入更改为实验。
此算法不包括Wikipedia article中提到的最终优化。