我提出的问题是将任何数字表示为四个素数的总和。
条件:
我做了什么:
使用Eratosthenes的筛子,我计算了所有素数,直到指定的数字。
查找了一个名为Goldbach猜想的概念,该概念将偶数数表示为两个素数的总和。
然而,我被困在那之外。 任何人都可以帮我解决一下你可能采取的方法吗?
Eratosthenes的筛子花了两秒钟来计算质量高达100,000的数量。
答案 0 :(得分:16)
随着时间的推移你仍然可以。由于Goldbach猜想,每个偶数大于或等于8可以表示为2,2和另外两个素数的总和。每个大于或等于9的奇数可以表示为2,3和另外两个素数之和。找出素数不应该花太长时间。
编辑:实际上,你可以显着加快这个速度:对于任何偶数N,找到小于或等于N-7的最大素数并选择该素数和3,然后寻找另外两个素数以适合你的总和。对于任何奇数N,找到大于或等于N-6的最大素数并选择它和两个,然后再选择两个素数。
答案 1 :(得分:4)
您可以通过注意一个简单的事实来减少所需的搜索范围:当您总结两个数字时,总和的最后一位数将是两个数字的最后一位数之和的最后一位数。例如2345 + 24323 = 26668和5 + 3 = 8;如果最后一位数字总和为2位数字,请使用其最后一位数字,例如。 2345 + 5436 = 7781 5 + 6 = 11,其最后一位为1。
所以,按照之前建议的算法:
例如,
对于像34565这样的数字,最后一位是5,组件来自(0,5),(1,4),(2,3),(3,2),(4,1) ),(5,0),(6,9),(7,8),(8,7),(9,6)。不包括重复项,我们留下(0,5),(1,4),(2,3), (6,9),(7,8)。 (预先计算所有最后的数字和 硬编码到您的程序中)。
如果N是原始数字,请从“0”框中选择每个数字M,检查(N-M)是否是“5”框等的成员,以获取所有可能的组合。如果是这样,你找到了答案!
答案 2 :(得分:2)
如果没有数量限制(100,000或更少),那么您的问题无法保证有解决方案:请参阅weak Goldbach conjecture。
然而,最有可能的是,至少对于计算结果范围内的数字而言......你确定你的问题不是表达任何数字 most 四个素数的总和吗? / p>
由于2,3,5,7,11,13,17,19,23提供了很多可能性,我会计算出数字,这些数字表示为这些数字中的3个的总和。 (例如2 + 3 + 5 = 10,2 + 3 + 7 = 2 + 5 + 7 = 12,3 + 5 + 7 = 15,2 + 3 + 11 = 16,2 + 5 + 11 = 18,3 + 5 + 11 = 19,2 + 7 + 11 = 20,...... 17 + 19 + 23 = 59。)
然后取任意数N,找到与N不同的最接近的素数,其中一个是3个小素数的预计算和。如果找不到解决方案,请尝试下一个最接近N-59的素数。如果仍然无效,请开始添加其他小素数。
使用prime gaps的知识来约束你的解决方案...... 155921(大于100,000)以下的素数最大的主要差距是86。
P.S。你的Eratosthenes筛子不应该花2秒钟N = 100,000。您只需要检查最大为100,000 = 316的平方根的除数。
答案 3 :(得分:1)
一旦你有一个素数列表,那么具体的数字不是knapsack problem吗?
N是你的容量,素数是你的物品。您对物品数量的限制为4。我会用动态编程来解决这个问题,这应该非常快。
答案 4 :(得分:0)
以下是我在评论中question referenced给出的推荐:
- 计算所有小于N的素数 Eratosthenes的筛子。
- 制表表格 两个素数之和的列表。
- 排序 列表。
- 检查是否有两个号码 在总和为N的列表中。
- 如果是,请打印出相应的四个 素数。
答案 5 :(得分:0)
这是一个 PHP 实现,在n = 99999下运行时间不到2秒:
function Eratosthenes($number)
{
static $primes = array();
if (empty($primes[$number]) === true)
{
$sqrt = sqrt($number);
$primes[$number] = array_merge(array(2), range(3, $number, 2));
for ($i = 2; $i <= $sqrt; ++$i)
{
foreach ($primes[$number] as $key => $value)
{
if (($value != $i) && ($value % $i == 0))
{
unset($primes[$number][$key]);
}
}
}
}
return $primes[$number];
}
$time = microtime(true);
$number = 99995;
$primes = array();
if ($number % 2 == 0)
{
$primes = array(2, 2);
}
else
{
$primes = array(2, 3);
}
$number -= array_sum($primes);
foreach (Eratosthenes($number) as $prime)
{
if (in_array($number - $prime, Eratosthenes($number)))
{
$primes[] = $prime;
$primes[] = $number - $prime;
die(implode(' + ', $primes) . ' (' . (microtime(true) - $time) . ')');
}
}
当然,除非你(错误地)将1视为素数,否则它将不适用于8以下的数字。
答案 6 :(得分:0)
关于Sieve的主题,我认为这是一个未被优化的,“愚蠢”的实现:
std::vector<int> primes(int n) {
std::vector<int> s(n+1);
for (int i = 2; i * i <= n; ++i) {
if (s[i] == 0) {
for (int j = 2*i; j <= n; j += i) {
s[j] = 1;
}
}
}
std::vector<int> p;
for (int i = 2; i <= n; ++i) {
if (s[i] == 0) {
p.push_back(i);
}
}
// std::copy(p.begin(), p.end(), std::ostream_iterator<int>(std::cout, ", "));
return p;
}
对我而言,它会在一小段时间内运行(n = 100000)。
答案 7 :(得分:0)
您的筛子实施存在严重问题。我刚刚在Delphi中实现它,在我的Intel Core i7 CPU上,主频为2.93 GHz,所需时间不到1毫秒(0.37 ms)!
我使用了以下代码:
program Sieve;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
const
N = 100000;
var
i, j: integer;
tc1, tc2, freq: Int64;
Arr: packed array[2..N] of boolean;
begin
FillChar(Arr, length(Arr) * sizeof(boolean), 1);
QueryPerformanceFrequency(freq);
QueryPerformanceCounter(tc1);
for i := 2 to N div 2 do
if Arr[i] then
begin
j := 2*i;
while j <= N do
begin
Arr[j] := false;
inc(j, i);
end;
end;
QueryPerformanceCounter(tc2);
Writeln(FloatToStr((tc2 - tc1)/freq));
Writeln;
for i := 2 to 100 do
Writeln(IntToStr(i) + ': ' + BoolToStr(arr[i], true));
Writeln('...');
Readln;
end.
答案 8 :(得分:-3)
任何数字也包括小数,所以你也不能将它们表示为素数。还有其他数字,比如你不能做的9。没有1作为素数,你无法控制它。
我希望问题没有解决方案。