我需要测试通过无线电通信的设备的范围。 通信需要快速进行,但传输速度较慢 可容忍的,达到一定程度(比如说,约3分钟)。我需要测试一下 传输是否会每200英尺成功一次,直到失败,最多1600 脚。每200英尺将进行一次测试,需要3分钟 执行。
我天真地认为二元搜索是找到故障点的最有效方法,但考虑行程速度为200英尺/分钟,测试时间为3分钟。如果在500英尺处发生传输失败,二进制搜索不是找到故障点的最有效方法,如下所示。
只需走路并测试每一个点就可以更快地找到解决方案,只需12分钟,而二分搜索&测试需要16分钟。
我的问题:在旅行时间问题上,您如何计算解决方案的最有效途径?这叫什么(例如,二元旅行搜索等)?
答案 0 :(得分:3)
二进制搜索确实取决于O(1)
访问时间;例如,在链接列表中进行二进制搜索很少[但请参阅注释1],这基本上就是您正在做的事情,因为您似乎假设只有离散间隔值得测试。如果您正在寻求更准确的答案,您会发现二进制搜索允许任意精度,每次精度需要额外测试一次。
假设您甚至不知道最大值是什么。然后你不能先在中间测试,因为你不知道中间位置。相反,你可能会进行指数搜索限制(这是一种内部的二进制搜索);您首先在x
,然后2x
,然后4x
进行测试,直至达到大于最大值的点(信号未达到那么远)。 (x
是您感兴趣的最小答案;换句话说,如果x
处的第一次测试显示信号未达到,则您将停止。)在此阶段结束时,您对于某个整数2ix
,我会在i
,您将知道答案在2i-1x
和2ix
之间。
现在你可以实际进行二分查找,首先是2i-2x
。从那里开始,你可以向前或向后,但你一定会旅行2i-3x
,下一次你将旅行2i-4x
,等等。
总而言之,在第一阶段(搜索最大值),您走到2ix
,并进行了i
次测试。在第二阶段,二进制细化,您总共进行(2i-1-1)x
和i-1
次测试。你最终会在d
和2i-1
之间的2i
结束,所以最坏的情况下你会走3d
的最后一点(最好的,你会走路3d/2
)。您将完成的测试次数为2*ceil(log2(d/x)) - 1
,这是2*log2(d/x)
的一次测试。
在什么情况下你应该做二进制搜索算法呢?基本上,它取决于行程时间和测试时间的比率,以及所需的答案精度。简单的顺序算法在d
移动大小d/x
和x
测试后找到位置d/x
;上面的二进制搜索算法在最多d
旅行后找到位置3d
,但只进行2 log(d/x)
次测试。粗略地说,如果测试花费的成本是旅行d/x
的两倍以上,并且预期距离远远大于精度,那么您应该更喜欢二分搜索。
在您的示例中,您似乎希望结果的精度为200英尺;旅行时间为1分钟,测试时间为3分钟,是旅行时间的两倍以上。所以你应该更喜欢二分搜索,除非你期望在少量的精度倍数中找到答案(就像这样)。请注意,虽然二进制算法使用四个测试和1000英尺的行程(与三个测试相比,顺序算法600英尺),将精度提高到50英尺只会增加四个测试和150英尺的二进制算法,顺序算法需要20次测试。
注1:实际上,如果测试成本很高,那么使用上述算法二进制搜索链表可能是有意义的。假设测试的成本与列表中的索引不成比例,对于线性搜索和二进制搜索,搜索的复杂度将为O(N)
,但二进制搜索将进行O(log N)
测试和O(N)
步骤,而顺序搜索将执行O(N)
测试和O(N)
步骤。对于足够大的N,这没关系,但对于真实世界大小的N,它可能很重要。
答案 1 :(得分:0)
实际上,二分搜索可以在这里应用,但有几处变化。我们必须计算不是居中,而是要访问的最佳位置。
int length = maxUnchecked - minChecked;
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
因为我们需要找到沟通失败的第一个位置,有时我们必须回去,之后可以最佳地使用其他策略
int length = maxUnchecked - minChecked;
int whereToGo = 0;
if ( increase )
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
else
whereToGo = minChecked + (int)(length * factorDecrease) + stepDecrease;
所以,我们的任务 - 找出这样的最佳因子增加,factorDecrease,stepIncrease,stepDecrease,f(failPos)之和的值将是最小的。怎么样?如果n(总长度/ 200.0f)很小,全部强力会帮助你。否则你可以尝试使用遗传算法或简单的smth。
步骤精度= 1,步长= [0,n)。 因子eps - 1 /(4 * n),因子限制 - [0,1)。
现在,简单的代码(c#)来证明这一点:
class Program
{
static double factorIncrease;
static int stepIncrease;
static double factorDecrease;
static int stepDecrease;
static bool debug = false;
static int f(int lastPosition, int minChecked, int maxUnchecked, int last, int failPos, bool increase = true, int depth = 0)
{
if ( depth == 100 )
throw new Exception();
if ( maxUnchecked - minChecked <= 0 ) {
if ( debug )
Console.WriteLine("left: {0} right: {1}", minChecked, maxUnchecked);
return 0;
}
int length = maxUnchecked - minChecked;
int whereToGo = 0;
if ( increase )
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
else
whereToGo = minChecked + (int)(length * factorDecrease) + stepDecrease;
if ( whereToGo <= minChecked )
whereToGo = minChecked + 1;
if ( whereToGo >= maxUnchecked )
whereToGo = maxUnchecked;
int cur = Math.Abs(whereToGo - lastPosition) + 3;
if ( debug ) {
Console.WriteLine("left: {2} right: {3} whereToGo:{0} cur: {1}", whereToGo, cur, minChecked, maxUnchecked);
}
if ( failPos == whereToGo || whereToGo == maxUnchecked )
return cur + f(whereToGo, minChecked, whereToGo - 1, last, failPos, true & increase, depth + 1);
else if ( failPos < whereToGo )
return cur + f(whereToGo, minChecked, whereToGo, last, failPos, true & increase, depth + 1);
else
return cur + f(whereToGo, whereToGo, maxUnchecked, last, failPos, false, depth + 1);
}
static void Main(string[] args)
{
int n = 20;
int minSum = int.MaxValue;
var minFactorIncrease = 0.0;
var minStepIncrease = 0;
var minFactorDecrease = 0.0;
var minStepDecrease = 0;
var eps = 1 / (4.00 * (double)n);
for ( factorDecrease = 0.0; factorDecrease < 1; factorDecrease += eps )
for ( stepDecrease = 0; stepDecrease < n; stepDecrease++ )
for ( factorIncrease = 0.0; factorIncrease < 1; factorIncrease += eps )
for ( stepIncrease = 0; stepIncrease < n; stepIncrease++ ) {
int cur = 0;
for ( int i = 0; i < n; i++ ) {
try {
cur += f(0, -1, n - 1, n - 1, i);
}
catch {
Console.WriteLine("fail {0} {1} {2} {3} {4}", factorIncrease, stepIncrease, factorDecrease, stepDecrease, i);
return;
}
}
if ( cur < minSum ) {
minSum = cur;
minFactorIncrease = factorIncrease;
minStepIncrease = stepIncrease;
minFactorDecrease = factorDecrease;
minStepDecrease = stepDecrease;
}
}
Console.WriteLine("best - mathmin={4}, f++:{0} s++:{1} f--:{2} s--:{3}", minFactorIncrease, minStepIncrease, minFactorDecrease, minStepDecrease, minSum);
factorIncrease = minFactorIncrease;
factorDecrease = minFactorDecrease;
stepIncrease = minStepIncrease;
stepDecrease = minStepDecrease;
//debug =true;
for ( int i = 0; i < n; i++ )
Console.WriteLine("{0} {1}", 3 + i * 4, f(0, -1, n - 1, n - 1, i));
debug = true;
Console.WriteLine(f(0, -1, n - 1, n - 1, n - 1));
}
}
所以,有些值(f ++ - factorIncrease,s ++ - stepIncrease,f-- - factorDecrease):
n = 9 mathmin = 144, f++: 0,1(1) s++: 1 f--: 0,2(2) s--: 1
n = 20 mathmin = 562, f++: 0,1125 s++: 2 f--: 0,25 s--: 1
答案 2 :(得分:0)
根据您实际想要优化的内容,可能有一种方法可以找出最佳搜索模式。我认为你不想优化最坏的情况时间,因为许多搜索策略的最慢情况是在休息时间结束时,二进制搜索实际上非常好 - 你走到最后而不改变方向,你不会停顿很多。
您可能会考虑使用不同的二叉树,也许可以计算出平行所需的平均时间。二进制搜索是一种树,因此随着时间走路并进行测试 - 一个非常不平衡的树,其中每个节点至少有一个叶子连接到它。
当沿着这样一棵树追随时,你总是从你走过的一条线的另一端开始,在进行测量之前走一段距离,然后根据结果和树,停止或重复这个过程用一条较短的线,你在哪一端。
这为您提供了可以使用动态编程进行攻击的内容。假设您已经解决了长达N段的问题,因此您知道这些长度的最佳解决方案的成本。现在,您可以为N + 1段制定最佳解决方案。考虑以N + 1种可能的方式将N + 1段分成两部分。对于每种这样的方式,计算转移到其决策点并进行测量的成本,然后在决策点两侧的两个部分段中增加最佳解决方案的成本,可能加权以考虑结束这些部分的概率。通过考虑这些N + 1种可能的方法,您可以找出分割N + 1段的最佳方法及其成本,并继续,直到您为实际拥有的部分数量找出最佳解决方案。