如何在不计算所有组合的情况下检查是否存在可分割的组合?

时间:2018-12-12 14:17:58

标签: algorithm

我正在尝试编写一个程序,该程序告诉是否可以在给定的整数之间插入+或-(它们的值最多3个数字,它们的数量最多4个数字)以获得一个数字可被另一个数字整除(最多2位数字)。这些整数的数量(一个4位数字)使得无法计算所有组合,并且由于复杂度O(2 ^ n)(因为程序应该在几秒钟而不是几个世纪内计算出),就无法检查其中的任何整数是否可整除。 >

我的第一个想法是使用某种树并将结果的部分存储在内存中,这将对将来的计算有用。在开始计算之前,我还删除了所有自己可整除的数字(因为该数字不会改变结果的可除性)。那大大减少了计算数量,但是在几秒钟内计算出的最大数量仅为30。您有什么主意,什么数学规则可以解决该问题?

2 个答案:

答案 0 :(得分:1)

当且仅当x等于0模y时,数字x才能被y整除。

因此,您需要跟踪的是可以达到y模的值。

没有数字时,唯一的值是0。

添加数字时,您可以添加或减去该值,以便最多可以获取2个新值。

因此,对于每个阶段,只需检查每个可能的模值是否可达。

总体复杂度为O(n.y),其中n是要加/减的数字计数,y是必须被其整除的数字。

答案 1 :(得分:0)

我认为我可能误解了您算法的目标,但我很难相信任何现代计算机都需要花费超过几秒钟的时间。我不知道您在哪里可以制定出需要花费数百年才能解决这个问题的算法。

以下是基本的蛮力算法,该算法遍历对(i:1-1000, j:1-1000),并计算|i-j|i+j之间的共享除数的完整列表。如果仍不能解决您的问题,请尝试使用简单的英语来澄清算法,而不用跳过单词(即“ Amount of”可能前面应有“ The”)。

function getDivisors(n: number): number[] {
  let i: number = 2;
  let divisors: number[] = [];
  for (i; i < Math.sqrt(n); i++) {
    if (n % i == 0) {
      divisors.push(i);
    }
  }
  return divisors;
}

function existsCombination(n: number, m: number): number[] {
  let dPlus: number[] = getDivisors(n+m);
  let dMinus: number[] = getDivisors(Math.abs(n-m));
  return dPlus.filter((d: number) => dMinus.indexOf(d) !== -1);
}

for (let i: number = 0; i < 1000; i++) {
  for (let j: number = 0; j < 1000; j++) {
    let common: number[] = existsCombination(i, j);
    if (common.length > 0) {
    console.log(`(i, j): (${i}, ${j}) => (${Math.abs(i-j)},${i+j})
    common divsiors: ${existsCombination(i, j)}`);
    }
  }
}