欧拉计划 60

质数3, 7, 109, 和 673是值得注意的。将其中任意两个质数以任何顺序相连接产生的结果都是质数。
例如,取7和109,连接而成的7109和1097都是质数。这四个质数的和是792,这也是满足这个性质的四个质数集合的最小总和。

找出满足这个性质的五个质数的集合中,集合数之和最小的。算出这个最小的和。

import time


def get_primes(n):
    """ n以下质数 """
    n_set = set(range(3, n, 2))
    for i in range(3, n, 2):
        if i in n_set:
            i_set = set(range(i * 2, n, i))
            n_set -= i_set
    return n_set


def is_prime(x):
    """ x是否质数 """
    if x < n_max:
        if x in primes_set:
            return True
        else:
            return False
    x_sqrt = int(pow(x, 0.5))
    l = [2]
    l.extend(range(3, x_sqrt + 1, 2))
    for i in l:
        if x % i == 0:
            return False
    return True


def check_prime_pair(p1, p2):
    """ 将其中任意两个质数以任何顺序相连接产生的结果都是质数 """
    p1_p2 = int('%d%d' % (p1, p2))
    if p1_p2 not in primes_set:
        if not is_prime(p1_p2):
            return False
    p2_p1 = int('%d%d' % (p2, p1))
    if p2_p1 not in primes_set:
        if not is_prime(p2_p1):
            return False
    return True


def prime_pair(p):
    """ 能与p组合以任何顺序相连接产生的结果都是质数的质数集 """
    if p in primes_dict:
        return primes_dict[p]
    primes = set()
    for j in range(primes_list.index(p) + 1, len(primes_list)):
        p_ = primes_list[j]
        if check_prime_pair(p, p_):
            primes.add(p_)
    primes_dict[p] = primes
    return primes


def get_prime_set(p, pairs, sum_max):
    """ 递归,五个质数的集合 """
    if sum(p) + (5 - len(p)) * max(p) >= sum_max:
        return sum_max
    if len(p) == 4:
        p.add(min(pairs))
        print(p)
        return sum(p)
    for pp in pairs:        
        pairs_ = pairs & prime_pair(pp)
        if len(pairs_) == 0:
            continue
        p_ = p.copy()
        p_.add(pp)
        sum_max_ = get_prime_set(p_, pairs_, sum_max)
        if sum_max_ < sum_max:
            sum_max = sum_max_
    return sum_max


t1 = time.time()
n_max = 10000
primes_set = get_primes(n_max) - {5}
sum_max = float('inf')
primes_dict = {}
# 按与3的余数划分质数集
# 余数为1的数只能与余数为1的数和3组合
# 余数为2的数只能与余数为2的数和3组合
for mod_3 in [2, 1]:
    primes_list = [p for p in primes_set if p % 3 != mod_3]
    primes_list.sort()
    for i1 in range(len(primes_list)):
        v1 = primes_list[i1]
        if v1 * 5 >= sum_max:
            break
        v1_prime_pair = prime_pair(v1)

        for i2 in range(i1 + 1, len(primes_list)):
            v2 = primes_list[i2]
            if v1 + v2 * 4 >= sum_max:
                break
            if v2 not in v1_prime_pair:
                continue
            v2_prime_pair = prime_pair(v2)

            for i3 in range(i2 + 1, len(primes_list)):
                v3 = primes_list[i3]
                if v1 + v2 + v3 * 3 >= sum_max:
                    break
                if v3 not in v1_prime_pair or v3 not in v2_prime_pair:
                    continue
                v3_prime_pair = prime_pair(v3)

                for i4 in range(i3 + 1, len(primes_list)):
                    v4 = primes_list[i4]
                    if v1 + v2 + v3 + v4 * 2 >= sum_max:
                        break
                    if v4 not in v1_prime_pair or v4 not in v2_prime_pair or v4 not in v3_prime_pair:
                        continue
                    v4_prime_pair = prime_pair(v4)

                    for i5 in range(i4 + 1, len(primes_list)):
                        v5 = primes_list[i5]
                        if v1 + v2 + v3 + v4 + v5 >= sum_max:
                            break
                        if v5 not in v1_prime_pair or v5 not in v2_prime_pair or v5 not in v3_prime_pair or v5 not in v4_prime_pair:
                            continue

                        sum_max = v1 + v2 + v3 + v4 + v5
                        print(v1, v2, v3, v4, v5)
print(sum_max)
t2 = time.time()
print(t2 - t1)


t1 = time.time()
n_max = 10000
primes_set = get_primes(n_max) - {5}
primes_dict = {}
sum_max = float('inf')
# 按与3的余数划分质数集
# 余数为1的数只能与余数为1的数和3组合
# 余数为2的数只能与余数为2的数和3组合
for mod_3 in [2, 1]:
    primes_list = [p for p in primes_set if p % 3 != mod_3]
    primes_list.sort()    
    for i in primes_list:
        sum_max = get_prime_set({i}, prime_pair(i), sum_max)
print(sum_max)
t2 = time.time()
print(t2 - t1)

你可能感兴趣的:(欧拉计划)