python要发就发

问题描述

        1898——要发就发。请将不超过1993的所有素数从小到大排成第一行,第二行上的每个数都等它上面相邻两个素数之差。编程求出:第二行数中是否存在若干个连续的整数,它们的和恰好为1898?假如存在的话,又有几种这样的情况?

        我们假设有一个连续的素数列表P恰好满足上面问题的要求,那么我们来分析一下这个问题。第一行为P[0],P[1],···,P[n],第二行为P[1] - P[0],P[2] - P[1],···,P[n] - P[n-1]。把第二行的数加起来为P[n] - P[0],所以P[n] - P[0] = 1898。推导过程如下图所示:

所以这个问题的本质就是,在小于等于1993的素数中是否存在两个素数之差等于1898。

要发就发

        既然要发就发问题的本质就是找出小于等于1993的素数中是否存在两个素数之差等于1898。那么我们就可以先制作一个用于生成素数的生成器,来把小于等于1993的所有素数都列出来。再到这个素数列表中寻找是否存在两个素数之差等于1898,如果存在就把它们输出来。

素数生成器

        首先制作一个素数生成器,来帮我们生成素数。我们这里使用埃氏筛法来生成素数,代码如下:

def primes_generator(n):
    """
    素数生成器

    :param n: 生成的最后一个素数小于等于n
    :return: Generator
    """
    yield 2  # 素数生成器遇到第一个next函数时返回2,并等待下一个next函数
    primes = list(range(3, n + 1, 2))  # 创建第一个元素为3最后一个元素小于n+1的奇数列表
    while primes:  # primes为空列表时结束循环
        yield primes[0]  # 素数生成器遇到next函数时返回列表primes的第一个元素,并等待下一个next函数
        primes = [i for i in primes if i % primes[0] > 0]  # 使用列表生成器把列表primes中的每一个元素都对primes的第一个元素取余,如果余数大于0则在新列表中添加该元素,最后返回新列表赋值给primes

要发就发执行函数

        素数生成器我们做好了,可以利用素数生成器来快速生成我们需要的素数了。现在只需要设计一段程序来找出在不超过1993的素数中是否存在两个素数之差为1898。我们先用最大的素数作为被减数从第一个素数2开始尝试相减,然后逐个向后尝试,看到哪一个素数时差值小于等于1898。如果差值等于1898就说明找到了一组解,如果差值小于了1898就没有必要再向后尝试了,直接使用第二大的素数作为被减数来尝试找解,如此循环,一直到被减素数小于1898时就不用再找了(自己都小于1898了还去减一个数就更小了)。代码如下:

def primes_sum_1898(big, primes_sum):
    """
    要发就发问题

    :param big: 不大于某个数
    :param primes_sum: 连续素数之和
    :return:
    """
    primes_list = list(primes_generator(big))  # 使用list函数把素数生成器中的生成的素数全部取出来变成一个素数列表
    for i in primes_list[::-1]:  # 逆序输出素数列表
        if i < primes_sum:  # 判断素数i是否小于连续素数之和
            break  # i小于连续素数之和时结束循环
        for n in primes_list:  # 正序输出素数列表
            if i - n < primes_sum:  # 判断两个素数之差是否小于连续素数之和
                break  # 两个素数之差小于连续素数之和时结束循环
            elif i - n == primes_sum:  # 判断两个素数之差是否等于连续素数之和
                print(primes_list[primes_list.index(n):primes_list.index(i)+1])  # 打印出满足条件的连续素数列表

完整代码

        组合素数生成器和要发就发执行函数,我们就能得到一个解决要发就发问题的程序。完整代码如下:

def primes_generator(n: int):
    """
    素数生成器

    :param n: 生成的最后一个素数小于等于n
    :return: Generator
    """
    yield 2  # 素数生成器遇到第一个next函数时返回2,并等待下一个next函数
    primes = list(range(3, n + 1, 2))  # 创建第一个元素为3最后一个元素小于n+1的奇数列表
    while primes:  # primes为空列表时结束循环
        yield primes[0]  # 素数生成器遇到next函数时返回列表primes的第一个元素,并等待下一个next函数
        primes = [i for i in primes if i % primes[0] > 0]  # 使用列表生成器把列表primes中的每一个元素都对primes的第一个元素取余,如果余数大于0则在新列表中添加该元素,最后返回新列表赋值给primes


def primes_sum_1898(big: int, primes_sum: int):
    """
    要发就发问题

    :param big: 不大于某个数
    :param primes_sum: 连续素数之和
    :return:
    """
    primes_list = list(primes_generator(big))  # 使用list函数把素数生成器中的生成的素数全部取出来变成一个素数列表
    for i in primes_list[::-1]:  # 逆序输出素数列表
        if i < primes_sum:  # 判断素数i是否小于连续素数之和
            break  # i小于连续素数之和时结束循环
        for n in primes_list:  # 正序输出素数列表
            if i - n < primes_sum:  # 判断两个素数之差是否小于连续素数之和
                break  # 两个素数之差小于连续素数之和时结束循环
            elif i - n == primes_sum:  # 判断两个素数之差是否等于连续素数之和
                print(primes_list[primes_list.index(n):primes_list.index(i)+1])  # 打印出满足条件的连续素数列表


primes_sum_1898(1993, 1898)

执行结果如下:

我们可以看到要发就发问题有3组解,第一组为89到1987的连续素数,第二组为53到1951的连续素数,第三组为3到1901的连续素数。有了上面这个程序,我们就可以轻松解决要发就发的同类问题了。

猜你喜欢

转载自blog.csdn.net/qq_40148262/article/details/130992581