C++ 查找给定素数列表中影响因子的最近数

C++ 查找给定素数列表中影响因子的最近数,c++,algorithm,math,C++,Algorithm,Math,假设我有一个数字,我可以找到组成这个数字的所有素因子。例如,6000是2^4*3*5^3 如果我有一个不能很好分解的数字(给定一个可接受的素数列表),我如何才能找到下一个最接近的数字?例如,给定数字5917,与素数2、3、5、7列表相关的最接近的数字是什么?在这个例子中是6000 我有办法用蛮力找到答案,但必须有一个更优雅的解决方案 const UInt32 num = 5917; const CVector<UInt32> primes = { 2, 3, 5, 7 }; cons

假设我有一个数字,我可以找到组成这个数字的所有素因子。例如,6000是2^4*3*5^3

如果我有一个不能很好分解的数字(给定一个可接受的素数列表),我如何才能找到下一个最接近的数字?例如,给定数字5917,与素数2、3、5、7列表相关的最接近的数字是什么?在这个例子中是6000

我有办法用蛮力找到答案,但必须有一个更优雅的解决方案

const UInt32 num = 5917;
const CVector<UInt32> primes = { 2, 3, 5, 7 };
const size_t size = primes.size();

UInt32 x = num;
while (x < num * 2)
{
    const UInt32 y = x;
    for(size_t i = 0; i < size && x > 1; ++i)
    {
        while(x % primes[i] == 0)
        {
            x /= primes[i];
        }
    }

    if (x == 1)
    {
        cout << "Found " << y << endl;
        break;
    }
    else
    {
        x = y + 1;
    }
}
const UInt32 num=5917;
常数向量素数={2,3,5,7};
常量size\u t size=primes.size();
UInt32 x=num;
而(x1;++i)
{
而(x%素数[i]==0)
{
x/=素数[i];
}
}
如果(x==1)
{

我们的想法是,检查所有可接受的素数的可能产物,并选择最好的

要实现这一点,使用递归是最简单的,但可能不是最有效的。创建一个递归函数,通过逐个添加所有可接受的素数来“检查”临时乘积。要记住最佳结果,最简单的方法是使用全局变量

int g_result;

void check(int num, int product, const vector<int>& primes)
{
    if (product >= num)
    {
        g_result = std::min(g_result, product);
    }
    else
    {
        for (int prime: primes)
            check(num, product * prime, primes);
    }
}

...
int main()
{
    g_result = INT_MAX;
    vector<int> primes = { 2, 3, 5, 7 };
    check(5917, 1, primes);
    std::cout << g_result;
}
int g_结果;
无效检查(整数、整数乘积、常量向量和素数)
{
如果(产品>=num)
{
g_结果=标准::最小值(g_结果,产品);
}
其他的
{
for(整数素数:素数)
检查(数量,产品*素数,素数);
}
}
...
int main()
{
g_结果=INT_MAX;
向量素数={2,3,5,7};
检查(5917,1,素数);

std::cout您可以尝试生成所有可能的产品,而不是通过重复分解来获得答案,直到您枚举
target*minPrime
下的所有产品,其中
minPrime
是集合中最小的素数

从一个由
1
组成的集合开始。每次迭代都会尝试将当前集合中的每个数字乘以每个素数。如果在最大值下找到一个新数字,则会将其添加到当前集合中。该过程将自身重复,直到无法添加新数字为止

在你的情况下,第一代是

1 2 3 5 7
下一代将是

1 2 3 4 5 6 7 9 10 14 15 21 25 35 49 
之后你会看到

第三代

1 2 3 4 5 6 7 8 9 10 12 14 15 18 20 21 25 27 28 30 35 42 45 49 50 63 70 75 98 105 125 147 175 245 343
第四代

1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 35 36 40 42 45 49 50 54 56 60 63 70 75 81 84 90 98 100 105 125 126 135 140 147 150 175 189 196 210 225 245 250 294 315 343 350 375 441 490 525 625 686 735 875 1029 1225 1715 2401 
以此类推。十二代人之后,你的设定值将不再增长,此时你可以找到高于目标值的最小值


我建议以下解决方案。我假设素数是从低到高排序的。我还使用了方便的
向量
int
类型

vector<int> primes = { 2, 3, 5, 7 };
int num = 5917;
// initialize bestCandidate as a power of some prime greater than num
int bestCandidate = 1;
while (bestCandidate < num) bestCandidate *= primes[0];
set<int> s;
s.insert(1);
while (s.size()) {
    int current = *s.begin();
    s.erase(s.begin());
    for (auto p : primes) { // generate new candidates
        int newCandidate = current * p;
        if (newCandidate < num) {
            // new lower candidates should be stored.
            if (s.find(newCandidate) == s.end())
                s.insert(newCandidate);
        }
        else {
            if (newCandidate < bestCandidate) bestCandidate = newCandidate;
            break; // further iterations will generate only larger numbers
        }
    }
}
cout << bestCandidate;

拿对数来说,我们可以把它看作是子集和问题的一种变体。下面是一个JavaScript示例,它列举了刚好通过目标标记的不同组合

函数f(目标,素数){
target=Math.log(目标);
primes=primes.map(函数(x){return Math.log(x);});
var-best=primes[0]*Math.ceil(target/primes[0]);
var-stack=[[0,0]];
while(堆栈[0]!==未定义){
var params=stack.pop();
var t=参数[0];
var i=参数[1];
如果(t>目标){
if(t
数字6000和5880都是2,3,5,7-平滑的,5880比6000更接近5917。为什么6000是正确的答案?@user448810已有的答案将“下一个最近的数字”替换为“下一个更高的数字”,OP没有拒绝他们这个问题(使用抽象算法解决方案)讨论了。目前,我们正在使用n方法,总是往上走,但我不确定这是否必要。如果最近的一个较低,这可能会起作用,我们还没有进行分析。我肯定遗漏了一些东西。当6000不能被7整除时,答案是什么?我认为你的分析与我看到的结果吻合得很好。你的版本确实如此在输入范围更广的情况下,似乎效率最高。@steveo225 Ivan,我认为我的算法与你的算法有类似的想法,但我的算法只生成不同的组合,而不需要记忆集,请检查!比较steveo225测试代码中三个示例的迭代次数:target 5917:y我们的836,我的448;目标8192:你的948,我的491;目标262145:你的2895,我的1048。你的想法允许编写非常有效的解决方案。我根据你的方法创建了一个
c++
解决方案。但是我不会切换到
double
s,因为它会带来一些浮点错误,为了比较epsilon的两个双精度必需。例如,
f(10,[2,5])
将返回
16
,而不是
10
。@IvanGritsenko非常感谢您检查并解释对数!
vector<int> primes = { 2, 3, 5, 7, 11, 17, 23 };
int num = 100005917;
int bestCandidate = INT_MAX;
list<pair<int, int> > ls;
ls.push_back(make_pair(1, 0));
while (ls.size()) {
    long long currentProd = ls.front().first;
    int primesUsed = ls.front().second;
    ls.pop_front();
    int currentPrime = primes[primesUsed];
    while (currentProd < num) {
        if(primesUsed < primes.size() - 1)
            ls.push_back(make_pair(currentProd, primesUsed + 1));
        currentProd *= currentPrime;
    }
    bestCandidate = min((long long)bestCandidate, currentProd);
}
cout << bestCandidate;