这是2012年波兰大学生程序设计比赛的练习部分出现的问题。尽管我可以找到主要比赛的解决方案,但似乎在任何地方都找不到该问题的解决方案。
的问题是:给定一组的不同的正整数不大于中,找到大小具有1以外没有公约数的最小子集的为至多500,并且可以假设的溶液存在。
i ≠ j S g 2 g 3。。。g 10 g 2 g 3。。。克10 ≥ 3 × 5 × 7 × 11 × 。。。× 29 = 3234846615 > 10 9,这是一个矛盾。
但是,即使这样,直接的蛮力仍然太慢。还有其他想法吗?
这是2012年波兰大学生程序设计比赛的练习部分出现的问题。尽管我可以找到主要比赛的解决方案,但似乎在任何地方都找不到该问题的解决方案。
的问题是:给定一组的不同的正整数不大于中,找到大小具有1以外没有公约数的最小子集的为至多500,并且可以假设的溶液存在。
i ≠ j S g 2 g 3。。。g 10 g 2 g 3。。。克10 ≥ 3 × 5 × 7 × 11 × 。。。× 29 = 3234846615 > 10 9,这是一个矛盾。
但是,即使这样,直接的蛮力仍然太慢。还有其他想法吗?
Answers:
这个问题等效于以下问题,并且双向构造归约关系都很简单。
给定一个位向量列表,找到它们的最小数量,以使and所有结果均为。(∗ )
然后,我们将集合覆盖率减小为。通过集合覆盖,我的意思是给定集合的列表,找到覆盖它们并集的最小集合数。S 1,… ,S k
我们将集合中的元素排序为。令,其中如果,否则为0。请注意,此函数是双射,因此具有反函数。 ˚F (小号)= (1 - χ 一个1(小号),... ,1 - χ 一个Ñ(小号))χ X(小号)= 1 X ∈ 小号
现在,如果我们在上求解,则解决方案是,然后是设置封面的解决方案。f (S 1),… ,f (S k){ f (S b 1),… ,f (S b m)} { f − 1(S b 1),… ,f − 1(S b m)}
因此,我认为这个问题正在测试一个人修剪搜索空间的能力。
通过计算所有成对的gcd,删除重复项然后递归,可以相对有效地解决此问题。这是在重复执行之前删除重复项的操作,这样可以提高效率。
我将在下面更详细地说明该算法,但首先,它有助于定义二进制运算符。如果是正整数集,则定义小号,Ť
注意和(在您的问题中); 通常,甚至会小于上述两个界限中的任何一个,这有助于提高算法的效率。还要注意,我们可以用计算通过简单的枚举进行gcd操作。| 小号⊗ Ť | ≤ 10 9小号⊗ Ť 小号⊗ Ť | S | × | T |
使用该符号,这里是算法。令为数字输入集。计算,然后计算,然后,依此类推。找到最小使得但。然后,您知道最小的此类子集的大小为。如果您还想输出此类子集的具体示例,则通过保留反向指针,可以轻松地重构此类集。小号2 = 小号1 ⊗ 小号1 小号3 = 小号1 ⊗ 小号2 小号4 = 小号1 ⊗ 小号3 ķ 1 ∈ 小号ķ 1 ∉ 小号ķ - 1 ķ
这将是相对有效的,因为中间集的大小都不会增长到以上(实际上,它们的大小可能会小得多),并且运行时间大约需要 gcd操作。 500 × (| S 1 | + | S 2 | + ⋯ )
这是一种优化,可以进一步提高效率。基本上,您可以使用迭代加倍来找到最小的,使得中的。特别是,对于每个元素,我们跟踪的最集,其gcd为,大小为。(当删除重复项时,您将较小的子集来解决关系。)现在,与其计算九个集合的序列计算五个集合的序列,通过计算,然后,然后1 ∈ 小号ķ X ∈ 小号我š 1 X ≤ 我š 1,s ^ 2,S ^ 3,s ^ 4,... ,s ^ 9 s ^ 1,S ^ 2,S ^ 4,s ^ 8,š 9 š 2 = s ^ 1 ⊗ 小号1 小号4 = 小号2 ⊗ 小号2 小号小号9 = 小号1 × 小号8 ķ ∈ [ 1 ,2 ,4 ,8 ,9 ] 1 ∈ 小号ķ ķ 1 ∈ 小号ķ 1 1 小号ķ 1 ∈ 小号ķ,然后。转到时,找到第一个使得。一旦你找到使得,您可以立即停止:你能找到的最小的子集,其最大公因数通过查看相关联的子集。因此,您可以在达到设置为中的立即停止,如果找到较小的子集,则可以尽早停止。
这应该是省时和省空间的。为了节省空间,对于每个元素,您都不需要存储整个集合:足以存储两个反向指针(因此,您将gcd的的两个元素用于获取)和可选地,相应子集的大小。小号我,小号Ĵ X
原则上,您可以用任何其他加法链替换序列。我不知道其他加法链是否会更好。最佳选择可能取决于正确答案的分布以及集合的预期大小,这对我来说并不明确,但可能可以通过实验根据经验得出。小号ķ
鸣谢:感谢KWillets提出了将数字子集与每个元素一起存储的想法,该想法允许提前停止。
也许可以用另一种方式更快地查看它……小于的最大素数是31607,在2到31607之间的总数为3401个素数,不是一个很大的数。写下在质数上得到充分分解的每个数字,直到31607: 这里是1或大质数。然后,如果相应的向量是线性独立的(且它们的 s不同或均为1),则的集合就相对质数,并且您正在寻找矩阵的秩。 ai=p n i 1 1 p n i 2 2 …PiPiainijP