素数序列的回溯算法

Posted

技术标签:

【中文标题】素数序列的回溯算法【英文标题】:Backtracking algorithm for prime sequence 【发布时间】:2012-04-11 01:09:13 【问题描述】:

我在回溯时遇到问题,不确定我正在做的事情是否准确地回溯。

对于我的示例,我有 n 个整数,它将是 [5,6,7,8]。

我需要从这些整数中找出素数序列是否存在以及是否显示它。

这个例子的素数序列是 7,6,5,8 因为 7+6=13 6+5=11 5+8=13

为了得到答案,我可以遍历每个 n,然后尝试查看它是否是素数序列。

从 5 点开始:

5,6[7,8] 5,6,7[8]

因为 7+8 不是素数。进入下一个整数。

因为 5+7 不是素数。进入下一个整数。

5,8,[6,7]

因为 8+6 或 8+7 不是素数。你已经完成了 5 个。

6 点开始:

6,5[7,8] 6,5,8[7]

因为 7+8 不是素数。进入下一个整数。

6,7[5,8]

因为 7+5 或 7+8 不是素数。进入下一个整数。

因为 6+8 不是素数。你已经完成了 6 个。

7 点开始:

7,6[5,8] 7,6,5[8] 7,6,5,8

自从找到素数序列后结束。

那么如何通过回溯来解决这个问题呢?

【问题讨论】:

我很难说出您的实际问题是什么。请您澄清一下,好吗? 如何用递归回溯解决这个问题?在这个问题中究竟是什么回溯? 优化算法的一种方法是忽略它变为奇数、奇数(除了 1、1)或偶数的情况,因为它总是有一个偶数和并且唯一的偶数素数是 2。 @Claud25:好的,我试图解释这个问题,并向您介绍如何使用回溯来解决这个问题的核心思想。我注意到(见下面的答案)这不是你想在 C++ 中实现它的方式,因为它会创建一个很大的开销复制实例。这是逻辑算法,它隐藏在给定语言的实现细节后面(嗯,除了 Haskell)。 我相信我已经完成了该程序而没有回溯。我不知道您是否可以进一步帮助我,但感谢您提供任何帮助。 【参考方案1】:

在这种情况下,回溯的想法基本上是这样的:让我找到整个有效事物的子序列(或前缀)的延续。如果我成功了,我会将继续返回给我的调用者。如果我运气不好,我会要求我的来电者尝试不同的前缀。

更准确地说:

// call initially as Backtrack(epsilon, all numbers)
Backtrack(Sequence fixedPrefix, Set unbound) 
  if (unbound is empty) 
    return check(fixedPrefix);
  
  for all (element in unbound) 
    if (Backtrack(concat(fixedPrefix,element), setminus(unbound,element))
      return true;
  
  return false;

请注意,此算法只会告诉您序列是否存在(在 C++ 中直接实现会非常慢),但不会告诉您该序列是什么,但修改起来很简单。

无论如何,回溯中的“返回”发生在递归调用运气不佳的最后一行:这将提示调用实例尝试另一个前缀,所以控制流程有点颠倒。

【讨论】:

我还在努力理解。我知道这可能看起来很容易,但我无法掌握。如果我的固定前缀 = [5] 并且我的未绑定 = [6,7,8]。它检查未绑定的所有元素。然后它需要 6 并检查 5+6 是否是素数?那么如果是fixedPrefix变成[5,6],unbound变成[7,8]? @Claud25:不,这可能是一种优化。现在这只检查整个序列,一旦达到递归的最后一层。您可以已经丢弃在任何情况下都不会产生有效序列的前缀,但我没有在这个答案中包含这个,以使核心思想更加清晰。【参考方案2】:

您的函数(无论是否是伪代码)没有任何生产力。我实际上不确定它应该做什么。 IE。 u = 0; 紧随其后的是 if(u == 4); 并且您的 isPrime 函数始终传递给 (Integers[0]+integers[0])

我相信您所说的回溯更恰当地称为递归函数(可以调用自身的函数)。回溯是递归函数可以表现出的特定行为的不良(模糊)名称。

如果你想要一个这样的递归函数,你需要放弃它并重新开始。用简单的英语(或其他语言)写出函数应该做什么。然后,一旦您知道需要传递给它的内容、失败和成功之间的区别以及失败或成功时返回的内容(失败时需要如何修改向量),然后对其进行编码。

超级提示:对于小的整数选择,例如您提供的整数,请尝试 stl < algorithm > 中的 next_permutation() 以快速了解向量中可能的整数排列。

【讨论】:

显然我的伪代码是废话,但我确实在纸上和我的例子中用英语解决了这个问题。我只想知道如何通过回溯来完成我在纸上所做的事情。所以回溯只是一个递归函数,但如果它是死胡同就停止了吗? 用草率的英语:vector[n] + vector[n+1] 是素数吗?如果是这样,请尝试 vector[n+1] + vector[n+2] 再次调用该函数,将向量和 n+1 传递给它。如果是并且 n+1 是向量的最后一个值,则返回 true。如果没有,让函数交换向量中的一些值并返回 false。 旁注:如果您在递归函数中使用任何复杂类型(如 )并且可以允许对其进行更改,请通过引用传递。 IE。 bool Backtrack(<vector> & myVec, int n)

以上是关于素数序列的回溯算法的主要内容,如果未能解决你的问题,请参考以下文章

回溯算法的复杂度

数字方阵2 题解 回溯算法.md

回溯1--素数环

ACM/ICPC 之 最长公共子序列计数及其回溯算法(51Nod-1006(最长公共子序列))

搜索与回溯 - 素数环

五大常用算法:分治动态规划贪心回溯和分支界定