从质因数重建除数列表(递归)

发布于 2024-11-05 06:21:38 字数 1829 浏览 0 评论 0原文

我有一个数字的质因数列表,其形式如下: int[] 因子 = {因子数,因子1,幂次因子1,因子2,幂次因子2,...};

我想要得到相当于动态嵌套的 for 循环,它将产生所有因素,其中 for 循环看起来像这样:

int currentpod = 1;
for(int i=0;i<factors[2];i++)
{
    currentprod *= Math.Pow(factors[1],i);
    for(int j=0;j<factors[4];j++)
    {
         currentprod *= Math.Pow(factors[3],i);
         ...
         //When it hits the last level (i.e. the last prime in the list, it writes it to a list of divisors
         for(int k=0;k<factors[6];k++)
         {
              divisors.Add(Math.Pow(factors[5],k)*currentprod);
         }
    }
}

不幸的是,由于 currentprod 没有得到足够的重置,这段代码会崩溃。 这是我用来尝试完成此操作的实际代码:

        public static List<int> createdivisorlist(int level, List<int> factors, int[] prodsofar,List<int> listsofar)
    {
        if (level == factors[0])
        {
            prodsofar[0] = 1;
        }
        if (level > 1)
        {
            for (int i = 0; i <= 2*(factors[0]-level)+1; i++)
            {
                prodsofar[level-1] = prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i);
                listsofar =  createdivisorlist(level - 1, factors, prodsofar, listsofar);
            }
        }
        else
        {
            for (int i = 0; i <= factors.Last(); i++)
            {
                listsofar.Add(prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i));
                if (listsofar.Last() < 0)
                {
                    int p = 0;
                }
            }
            return listsofar;
        }
        return listsofar;
    }

原始参数是: 水平 = 因素[0] Factors = 上面指定格式的质因数列表 prodsofar[] = 所有元素均为 1 listofar = 空列表

我如何重置 prodsofar 以便它不会“爆炸”而只是执行我概述的操作? 注意:作为测试,使用 2310,因为在当前代码下,要添加的除数为负(int 溢出)。

I have a list of the prime factors of a number in the following form:
int[] factors = {number of factors,factor1,poweroffactor1,factor2,poweroffactor2,...};

I want to get the equivalent of dynamically nested for loops that will yield all the factors, where the for loops will look something like this:

int currentpod = 1;
for(int i=0;i<factors[2];i++)
{
    currentprod *= Math.Pow(factors[1],i);
    for(int j=0;j<factors[4];j++)
    {
         currentprod *= Math.Pow(factors[3],i);
         ...
         //When it hits the last level (i.e. the last prime in the list, it writes it to a list of divisors
         for(int k=0;k<factors[6];k++)
         {
              divisors.Add(Math.Pow(factors[5],k)*currentprod);
         }
    }
}

Unfortunately, this code blows up as currentprod does not get reset enough.
Here is the actual code that I am using to try an accomplish this:

        public static List<int> createdivisorlist(int level, List<int> factors, int[] prodsofar,List<int> listsofar)
    {
        if (level == factors[0])
        {
            prodsofar[0] = 1;
        }
        if (level > 1)
        {
            for (int i = 0; i <= 2*(factors[0]-level)+1; i++)
            {
                prodsofar[level-1] = prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i);
                listsofar =  createdivisorlist(level - 1, factors, prodsofar, listsofar);
            }
        }
        else
        {
            for (int i = 0; i <= factors.Last(); i++)
            {
                listsofar.Add(prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i));
                if (listsofar.Last() < 0)
                {
                    int p = 0;
                }
            }
            return listsofar;
        }
        return listsofar;
    }

the original arguments are:
level = factors[0]
factors = a list of the prime factors in the format specified above
prodsofar[] = all elements are 1
listsofar = an empty list

How can i reset prodsofar so that it does not "blow up" and instead just does what I outlined?
Note: as a test, use 2310, as under the current code, the divisor to be added is negative (int overflow).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等往事风中吹 2024-11-12 06:21:38

您想到的递归算法的想法是保留一个累积的除数列表。为此,以下代码是如何执行此操作的示例(保留您的符号:由于“除数”和“因子”的含义完全相同,因此多重术语很不幸):

public static List<int> divisors(int[] factors, List<int> foundfactors, int level)
{
    if(level > factors[0]) return foundfactors;

    int current = 1;
    List<int> curpowers = new List<int>();
    for(int i=0; i<factors[2*level]+1; ++i)
    {
        curpowers.Add(current);
        current *= factors[2*level-1];
    }
    List<int> newfactors = new List<int>();
    foreach(int d in foundfactors)
        foreach(int n in curpowers)
            newfactors.Add(d*n);
    return divisors(factors, newfactors, level + 1);
}

内容来调用它

    // 600 = 2^3 * 3^1 * 5^2
    int[] pfactors = new int[] {3, 2,3, 3,1, 5,2};
    List<int> foundfactors = new List<int> {1};
    List<int> ds = divisors(pfactors, foundfactors, 1);
    foreach(int d in ds) Console.WriteLine(d);

使用类似打印所有 24 个除数的 600。

The idea of the recursive algorithm you have in mind is to keep an accumulating list of divisors. For that, the following code is an example of how to do it (retaining your notation: since "divisors" and "factors" mean exactly the same thing, the multiple terminology is unfortunate):

public static List<int> divisors(int[] factors, List<int> foundfactors, int level)
{
    if(level > factors[0]) return foundfactors;

    int current = 1;
    List<int> curpowers = new List<int>();
    for(int i=0; i<factors[2*level]+1; ++i)
    {
        curpowers.Add(current);
        current *= factors[2*level-1];
    }
    List<int> newfactors = new List<int>();
    foreach(int d in foundfactors)
        foreach(int n in curpowers)
            newfactors.Add(d*n);
    return divisors(factors, newfactors, level + 1);
}

Call it with something like

    // 600 = 2^3 * 3^1 * 5^2
    int[] pfactors = new int[] {3, 2,3, 3,1, 5,2};
    List<int> foundfactors = new List<int> {1};
    List<int> ds = divisors(pfactors, foundfactors, 1);
    foreach(int d in ds) Console.WriteLine(d);

which prints all 24 divisors of 600.

水波映月 2024-11-12 06:21:38

这只是一个“生成所有组合”的问题。您可以使用您最喜欢的搜索引擎来查找在 C# 中执行此操作的方法; 这里是一个示例。

请注意,您需要将“素数 p 使用 k 次”映射到 {p, p, p, ...}(k 次)。

This is just a "generate all combinations" problem. You can use your favorite search engine to find ways of doing this in C#; here is one example.

Note that you'll need to need to map "prime p used k times" to {p, p, p, ...} (k times).

柒七 2024-11-12 06:21:38

这与已接受的答案类似 - 对于试图了解正在发生的事情的人来说可能会更清楚一些......

def divisors_from_primes(primes, v = 1)
  if primes.empty?
    puts v
    return
  end
  p = primes.keys.first
  m = primes[p]
  primes.delete(p)
  0.upto(m) do |power|
    divisors_from_primes(primes, v * (p**power))
  end  
  primes[p] = m
end

/* 72 = 2**3 * 3**2  */

divisors_from_primes({ 2 => 3, 3 => 2})

所以在这个例子(72)中,它基本上是以下的递归版本:

0.upto(3) do |twopower|
  0.upto(2) |threepower|
    puts 2**twopower * 3**threepower
  end
end

This is similar to the accepted answer - it may be a little clearer to someone trying to understand whats going on...

def divisors_from_primes(primes, v = 1)
  if primes.empty?
    puts v
    return
  end
  p = primes.keys.first
  m = primes[p]
  primes.delete(p)
  0.upto(m) do |power|
    divisors_from_primes(primes, v * (p**power))
  end  
  primes[p] = m
end

/* 72 = 2**3 * 3**2  */

divisors_from_primes({ 2 => 3, 3 => 2})

So in this example (72), its basically a recursive version of:

0.upto(3) do |twopower|
  0.upto(2) |threepower|
    puts 2**twopower * 3**threepower
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文