给定一个素数列表和一个因数分解模式,如何构造其因数分解符合给定模式的所有数

Given a list of primes and a factorization pattern, how to construct all numbers whose prime factorization matches the given pattern?

本文关键字:分解 模式 一个 何构造 数列 列表      更新时间:2023-10-16

虽然我已经试着在标题中总结了这个问题,但我认为如果我从一个问题的实例开始会更好:

素数列表= {2 3 5 7 11 13}
因子分解模式= {1 1 2 1}

对于上述输入,程序应该生成以下数字列表:
  • 2.3.5 ^ 2.7
  • 2.3.5 ^ 2.11
  • 2.3.5 ^ 2.13
  • 2.3.7 ^ 2.11
  • 2.3.7 ^ 2.13
  • 2.3.11 ^ 2.13
  • 2.5.7 ^ 2.11
  • 2.5.7 ^ 2.13
  • 2.7.11 ^ 2.13
  • 3.5.7 ^ 2.11
  • 3.5.7 ^ 2.13
  • 3.5.11 ^ 2.13
  • 3.7.11 ^ 2.13
  • 5.7.11 ^ 2.13
到目前为止,我明白,由于模式的长度是任意大的(素数列表也是如此),我需要使用递归函数来获得所有的组合。我真的,真的卡住了-如何制定函数的参数/何时调用等。这是我目前开发的内容:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
static const int factors[] = {2, 3, 5, 7, 11, 13};
vector<int> vFactors(factors, factors + sizeof(factors) / sizeof(factors[0]));
static const int powers[] = {1, 1, 2, 1};
vector<int> vPowers(powers, powers + sizeof(powers) / sizeof(powers[0]));
// currPIdx [in]  Denotes the index of Power array from which to start generating numbers
// currFidx [in]  Denotes the index of Factor array from which to start generating numbers
vector<int> getNumList(vector<int>& vPowers, vector<int>& vFactors, int currPIdx, int currFIdx)
{
    vector<int> vResult;
    if (currPIdx != vPowers.size() - 1)
    {
        for (int i = currPIdx + 1; i < vPowers.size(); ++i)
        {
            vector<int> vTempResult = getNumList(vPowers, vFactors, i, currFIdx + i);
            vResult.insert(vResult.end(), vTempResult.begin(), vTempResult.end());
        }
        int multFactor = pow((float) vFactors[currFIdx], vPowers[currPIdx]);
        for (int i = 0; i < vResult.size(); ++i)
            vResult[i] *= multFactor;
    }
    else
    {   // Terminating the recursive call
        for (int i = currFIdx; i < vFactors.size(); ++i)
        {
            int element = pow((float) vFactors[i], vPowers[currPIdx]);
            vResult.push_back(element);
        }
    }
    return vResult;
}
int main()
{
    vector<int> vNumList = getNumList(vPowers, vFactors, 0, 0);
    cout << "List of numbers: " << endl;
    for (int i = 0; i < vNumList.size(); ++i)
        cout << vNumList[i] << endl;
}

当我运行上面的代码时,我得到了一个不正确的列表:

List of numbers: 
66
78
650
14
22
26

我不知怎么地遇到了一个心理障碍,因为我似乎无法弄清楚如何适当地改变递归调用中的最后一个参数(我相信这是我的程序不工作的原因)!!

如果有人能够用缺失的逻辑来调整我的代码(或者甚至指出它-我不是在寻找一个完整的解决方案!),那将是非常棒的。如果您能将您的答案限制为标准c++,我将非常感激!

(如果有人注意到我遗漏了给定模式的排列,这将导致其他数字,如2.3.5.7^2等-别担心,我打算通过使用next_permutate对给定模式的所有可能排列重复此算法!)。

PS:不是作业/面试问题,只是一个非常有趣的欧拉项目问题的算法的一部分(我想你甚至可以猜到是哪个:))。

编辑:我已经自己解决了这个问题——我已经把它作为答案贴出来了。如果你喜欢它,请给它投票(我不能接受它作为答案,直到它得到比其他答案更多的投票!)…

暂时忘记分解。你要解决的问题是有两个列表P和F,并找出P在P和F在F中的所有可能的配对(P, F),这意味着你会有|P| * |P|-1…* |P|-(|F|-1)可能的配对(将P中的1赋值给F的第一个元素,留下|P|-1种匹配第二个元素的可能性,等等)。您可能希望在代码中分离出问题的这一部分。如果你这样递归,最后一步是从P中选择剩下的元素到f的最后一个元素,这有帮助吗?我必须承认,我对您的代码了解不够,无法提供适合您当前状态的答案,但这就是我通常处理它的方式。

这是我自己想出来的!下面是它的代码(我希望这是不言自明的,但如果有人需要更多细节,我可以澄清):

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
static const int factors[] = {2, 3, 5, 7, 11, 13};
vector<int> vFactors(factors, factors + sizeof(factors) / sizeof(factors[0]));
static const int powers[] = {1, 1, 2, 1};
vector<int> vPowers(powers, powers + sizeof(powers) / sizeof(powers[0]));
// idx - The index from which the rest of the factors are to be considered. 
//       0 <= idx < Factors.size() - Powers.size()
// lvl - The lvl of the depth-first tree
//       0 <= lvl < Powers.size()
// lvlProd - The product till the previous level for that index.
void generateNumList
(  
    vector<int>& vPowers, 
    vector<int>& vFactors,
    vector<int>& vNumList, 
    int idx, 
    int lvl, 
    long lvlProd
)
{
    // Terminating case
    if (lvl == vPowers.size() - 1)
    {
        long prod = pow((float) vFactors[idx], vPowers[lvl]) * lvlProd;
        vNumList.push_back(prod);
    }
    else
    {
        // Recursive case
        long tempLvlProd = lvlProd * pow((float) vFactors[idx], vPowers[lvl]);
        for (int i = idx + 1; i < vFactors.size(); ++i)
            generateNumList(vPowers, vFactors, vNumList, i, lvl + 1, 
                            tempLvlProd);
    }
}
vector<int> getNumList(vector<int>& vPowers, vector<int>& vFactors)
{
    vector<int> vNumList;
    for (int i = 0; i < vFactors.size(); ++i)
        generateNumList(vPowers, vFactors, vNumList, i, 0, 1);
    return vNumList;
}
int main()
{
    vector<int> vNumList = getNumList(vPowers, vFactors);
    cout << endl << "List of numbers (" << vNumList.size() << ") : " << endl;
    for (int i = 0; i < vNumList.size(); ++i)
        cout << vNumList[i] << endl;
}

以上代码的输出(我必须花很长时间才能在算法上消除重复条目!):

List of numbers (15) : 
1050
1650
1950
3234
3822
9438
5390
6370
15730
22022
8085
9555
23595
33033
55055
real    0m0.002s
user    0m0.001s
sys     0m0.001s