我真的不想让它来到这里,PE当然是我应该尝试自己解决问题。
前两个我在不到一个小时内完成了管理,不幸的是我完全陷入了问题3.现在我尝试了传统的分区试验方法,当然这太慢了,我试过优化通过除以 sqrt(n)的试验划分,但仍然太慢,无法获得600,851,475,143的最高素数因子。
现在我甚至试图使用 Eratosthenes的筛子这个,我不得不承认我几乎不理解,但它仍然没有削减它,首先"标记为"数字会导致抛出异常,因为当您尝试生成高达600,851,475,143的所有素数时,条目数量会变得巨大。
我被困了,坦率地说,我现在正处于开始对此感到恼火的地方..
这是我的代码:
class Program
{
// The prime factors of 13195 are 5, 7, 13 and 29.
// What is the largest prime factor of the number 600851475143 ?
static void Main(string[] args)
{
Console.WriteLine(GetHighestPrimeFactor(600851475143).ToString());
Console.ReadKey();
}
static List<long> GeneratePrimeNumbers(long n)
{
// Let's use the Sieve of Eratosthenes for this
var markedNumbers = new List<long>();
var primes = new List<long>();
for (long i = n / 2; i < n; i++)
{
// If this is false then this is a prime number, add it to the list of primes
if (!markedNumbers.Contains(i))
{
primes.Add(i);
for (long j = i; j <= n; j+= i)
{
markedNumbers.Add(j);
}
}
}
return primes;
}
static long GetHighestPrimeFactor(long n)
{
var primes = GeneratePrimeNumbers(n);
// Loop backwards and return when we hit the first prime number
for (long i = n / 2; i > 1; i--)
{
if (n % i == 0)
{
if (primes.Contains(i))
{
return i;
}
}
}
//Code should not reach this point of execution
return -1;
}
答案 0 :(得分:2)
PE的当然点是我应该自己尝试解决问题。
是的,所以这里有一些提示而不是答案。
我试图通过除以sqrt(n)
来优化除法
我不知道这有多大帮助。假设你试图找到最大的素数因子74. 74的平方根是8点。如何将74除以8.something帮助?
现在我甚至试图使用Eratosthenes的筛子
Sieve用于查找素数。你的理论是,你会发现所有素数达到所需的数量然后那些找到最大的数字除以?
对于大量人来说,计算成本太高了。
所以这是你的提示:
如果数字n> 0是素数然后它是它自己最大的素数除数。
如果数字n> 0是复合的,然后是x * y,其中两者都不是1.
这两个数字中的一个小于或等于n的平方根。
n的最大素因子等于x的最大素因子或y的最大素因子。
如果你不明白为什么其中一个事实是真的,那么在你做之前停下来思考一下。除非你感到寒冷,否则你将永远无法解决接下来的几个欧拉问题。
现在有了这些提示,您应该能够将问题分解为一系列较小的问题。
答案 1 :(得分:0)
我自己已经阅读了关于Eratosthenes筛选的信息,但我对素数分解技术知之甚少。我不确定从生成所有已知质数的列表开始是一个很好的技术。不是说它不好,我只是怀疑可能更实用的技术不采用这种方法,因为它会有巨大的空间需求。
除此之外,我会建议修补素数列表的内存使用问题。
首先,我会将GeneratePrimeNumbers的结果写入分段文件,而不是将它们添加到内存列表中,每个文件覆盖一些素数块(相当大但在容易加载到内存中的范围内)。也许作为第一行有关文件中最大/最小素数的一些信息。
在GeneratePrimeNumbers中,从包含最大素数的页面开始(将该页面从文件加载到列表中,选择一个C#数据类型,其中包含O(1)时间.Contains,我认为HashSet对此有好处),当你向后工作并交叉到一个新的段时,删除当前页面的素数列表并加载素数的新页面。这将解决您的内存使用问题。如果确保每个页面包含相同数量的素数(或者自上一页可能是部分的最大数量),那么您可以重用现有列表或使用容量==初始化列表到页面大小。无论你使用什么数据结构,它都可能在构造函数中有一个容量选项,你想传递它,因为它将确保它预先请求所需的内存量。如果你有300个素数,并且没有设置capcity,那么当你添加它时,列表的内部数组大小会加倍。例如,当它超过256时,它会在内部创建一个新的512项数组,并将256个项复制到新的512个数组。这意味着当跨越这样的边界时,列表使用三倍的内存量,因为它既有旧数组又有新数组,是旧数组的2倍。复制完成后,它不需要旧的数组。重点是,如果你没有预先设置容量,那么当你只需要大约三分之一的可用内存时,你可能会出现内存异常。
我可能会让GeneratePrimeNumbers检查预先存在的文件,如果传入的数字较大,那么只需跳到最大的现有页面并写入其他页面直到该值。我可能有一个索引文件,列出页面和开始/结束素数,这样你就不必读取一堆大文件来执行此检查,但我认为你可以通过开始/结束每个文件作为第一行,只读取第一行然后关闭文件。