我们正在寻找一种在O(N)下解决这个问题的算法。
给出两个实数a和b(不失一般性,你可以假设它们都在0和1之间) 在-N和N之间找到一个最小化表达式的整数:
| a n - b - round(a n - b)|
我们认为欧几里得算法可能对此有效,但无法弄清楚。看起来应该有更快的方法来实现这一点,而不是通过对整数n进行详尽的搜索。
注意:在我们的情况下,a和b可能经常更改,因此可以修复查找表的a和b,它会变得有点难看,因为N也可以变化。还没有详细查看查询表,看看我们可以将它作为N的函数得到多小。
答案 0 :(得分:1)
您正在有效地搜索使表达式aN - b
尽可能接近整数的整数N. a
和b
已修复吗?如果是,您可以预先计算查找表并使用O(1): - )
如果不考虑为所有整数aN
寻找使I + b
接近I
的N.
答案 1 :(得分:1)
听起来你可能正在寻找像continued fractions ......
这样的东西他们是如何相关的?假设您可以用有理数b1 / b2替换b。现在你正在寻找整数n和m,使得a-b1 / b2大约是m。换句话说,你正在寻找n和m使得(m +(b1 / b2))/ n =(mb2 + b1)/ nb1,一个有理数,大约是a。设置a1 = mb2 + b1和a2 = nb1。从连续的分数近似中找出a1和a2的值,并求解n和m。
另一种方法可能是:
我不太确定它会起作用。 a所需的准确度取决于n和b。
答案 2 :(得分:1)
您可以计算比率a / b的连续分数。当分母大于N
或者近似值足够好时,您可以停止。
// Initialize:
double ratio = a / b;
int ak = (int)(ratio);
double remainder = ratio - ak;
int n0 = 1;
int d0 = 0;
int n1 = ak;
int d1 = 1;
do {
ratio = 1 / remainder;
ak = (int)ratio;
int n2 = ak * n1 + n0;
int d2 = ak * d1 + d0;
n0 = n1;
d0 = d1;
n1 = n2;
d1 = d2;
remainder = ratio - ak;
} while (d1 < N);
您要查找的n
的值为d0
(如果d1
仍小于N
,则为{{1}}。
这并不一定能给你最小的解决方案,但它可能是一个非常好的近似值。
答案 3 :(得分:0)
首先,让我们考虑一个更简单的情况,其中b = 0且0 <0。 a&lt; 1. F(a,n)= | an-round(an)|
让step_size = 1
Step 1. Let v=a
Step 2. Let period size p = upper_round( 1/v ).
Step 3. Now, for n=1..p, there must be a number i such that F(v,i) < v.
Step 4. v = F(v,i), step_size = stepsize * i
Step 5. Go to step 2
如您所见,您可以将F(v,*)降低到您想要的任何级别。最终解决方案n = step_size。