将一个点变成另一个点的算法
Posted
技术标签:
【中文标题】将一个点变成另一个点的算法【英文标题】:Algorithm to turn one point into another 【发布时间】:2015-09-05 08:42:06 【问题描述】:输入四个整数,格式为 (a,b)
和 (c,d)
。
确定是否可以从(a,b)
获取(c,d)
,如果在每个步骤中您可以在操作(a+b,b)
或(a,a+b)
之间进行选择。
例如,(1,2) -> (3,2) -> (5,2) -> (5,7) -> (12,7) -> (12,19) -> ...
我尝试用 a+bx = c 和 ax +b = d 解决问题,但没有奏效。有什么想法吗?
【问题讨论】:
请您介意显示不起作用的代码。这样有人可能会帮助您修复它。 数字可以是负数吗? 【参考方案1】:可达点的模式看起来并不简单。您可以将其视为具有合理斜率的斜线网络,从可达点开始。
这是(1, 2)
的模式。这些字母对应着连续的“世代”。
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. A . B . C . D . E . F . G . H . I . J . K . L . M
. B . . C . . D . . E . . F . . G . . H . . I . . J
. C . . . D . . . E . . . F . . . G . . . H . . . I
. D . C . . E . D . . F . E . . G . F . . H . G . .
. E . . . . . F . . . . . G . . . . . H . . . . . I
. F . . D D . . G . . E E . . H . . F F . . I . . G
. G . D . . . . . H . E . . . . . I . F . . . . . J
. H . . . E . E . . I . . . F . F . . J . . . G . G
. I . . . . . E . . . J . . . . . F . . . K . . . .
. J . E E . F . . F . . K . F F . G . . G . . L . G
. K . . . E . . . . . . . L . . . F . . . . . . . M
. L . . . . . G E F F G . . M . . . . . H F G G H .
. M . F . F . . . . . . . . . N . G . G . . . . . .
. N . . F . . . H . . . . H . . O . . G . . . I . .
. O . . . . . F . . . G . G . . . P . . . . . G . .
. P . G . F G F . I . . . G . I . . Q . H . G H G .
. Q . . . . . . . . . F . F . . . . . R . . . . . .
. R . . G G . . . . J F F H . . H J . . S . . H H .
. S . H . . . H . G . . . . . . . . . . . T . I . .
. T . . . . . . F . . K . . . . H H . K . . U . . .
. U . . . G . . . G . . . . . I . . . I . . . V . .
. V . I H . H G I . G . L . G . . . G . . L . . W .
. W . . . H . G . . . H . . . . . . . . . . . . . X
. X . . . . . . . . . . . M G . G J G I . I J M . .
由于乍一看这在数学上并不容易处理,因此可以通过从 (c, d)
回溯找到算法解决方案。
(a, b)= (1, 2)
def Backtrack(c, d):
if c == a and d == b:
print "Reachable !"
return
if d > 0 and c >= d:
Backtrack(c - d, d)
if c > 0 and d >= c:
Backtrack(c, d - c)
Backtrack(9, 8)
Reachable !
除非c == d
导致快速终止,否则最多只进行一次递归调用,这样调用次数就不会呈指数增长。
【讨论】:
你图中的模式很有趣。每行中的点数遵循重复模式。第一行 1 点,然后 2 点,然后 3。之后是 (1,2), (5), (2,0,2), (1,5), (3,1,2), (5, 3), (1,0,1,2,2)。【参考方案2】:也许有一个我不知道的方程式的优雅数学解决方案,但对我来说,这看起来像是一个搜索问题。我们有一个起点 (a, b) 和一个终点 (c, d),在搜索的每个点我们都可以进行两次移动:要么进入状态 (a+b, b) 要么 (a, a +b)。一个简单的递归深度优先搜索可以做到。这里唯一棘手的一点是确定何时停止搜索。
让我们首先解决所有整数都是正数的情况。在这种情况下,我们无法希望找到解决方案的限制条件很明确:当 a 超过 c 或 b 超过 d 时,我们无法希望在树的这个分支上找到更低的解决方案:
bool pathExistsForPositive(int a, int b, int c, int d)
if (a == c && b == d) return true; // success condition
if (a > c || b > d) return false; // limiting condition
return pathExistsForPositive(a+b, b, c, d)
|| pathExistsForPositive(a, a+b, c, d);
现在,将这种情况推广到数字不是正数的情况比较棘手,但可行。我希望这种直觉有所帮助。尝试考虑在这种情况下何时必须停止搜索。
【讨论】:
【参考方案3】:您可以循环查找所有可能的解决方案
var sols = [[3,2]];
var sols2 = [];
for(depth=1;depth<5;++depth)
for(j=0;j<sols.length;++j)
var sol = sols[j];
var sol1 = [sol[0]+sol[1],sol[1]];
var sol2 = [sol[0],sol[0]+sol[1]];
sols2.push(sol1,sol2);
console.log(sol1);
console.log(sol2);
sols = sols2;
sols2 = [];
console.log();
这只是找到所有可能的解决方案。您可以优化代码以过滤掉所有失败的代码。
快速 gcd 检查将消除任何无法工作的输入。
【讨论】:
这种方法会出现指数爆炸,不能将深度限制为5。以上是关于将一个点变成另一个点的算法的主要内容,如果未能解决你的问题,请参考以下文章