Project Euler Problem 86 (Python和C++代码实现和解析)

100 篇文章 3 订阅
87 篇文章 1 订阅

Problem 86 : Cuboid route

A spider, S, sits in one corner of a cuboid room, measuring 6 by 5 by 3, and a fly, F, sits in the opposite corner. By travelling on the surfaces of the room the shortest “straight line” distance from S to F is 10 and the path is shown on the diagram.

在这里插入图片描述
However, there are up to three “shortest” path candidates for any given cuboid and the shortest route doesn’t always have integer length.

It can be shown that there are exactly 2060 distinct cuboids, ignoring rotations, with integer dimensions, up to a maximum size of M by M by M, for which the shortest route has integer length when M = 100. This is the least value of M for which the number of solutions first exceeds two thousand; the number of solutions when M = 99 is 1975.

Find the least value of M such that the number of solutions first exceeds one million.

1. 欧拉项目第86道题 长方体路径

蜘蛛S位于一个6乘5乘3大小的长方体屋子的一角,而苍蝇F则恰好位于其对角。沿着屋子的表面,从S到F的最短“直线”距离是10,路径如下图所示:
在这里插入图片描述
然而,对于任意长方体,“最短”路径实际上一共有三种可能;而且,最短路径的长度也并不一定为整数。

当M=100时,若不考虑旋转,所有长、宽、高均不超过M且为整数的长方体中,对角的最短距离是整数的恰好有2060个;这是使得该数目超过两千的最小M值;当M=99时,该数目为1975。

找出使得方案数超过一百万的最小的M的值。

2. 求解分析

这道题其实求解挺难的。

首先,如果M不大时,我们可以使用枚举判断,把一个长方体(的盒子)展开成平面,然后就很直观的知道SF之间的直线距离有三种可能,找出距离最短的一条路线。

其次,如果M比较大,SF之间的立方体的路线特别大时,使用暴力求解特别费时,因此,需要探究算法: A143714 Number of pairs (a,b), 1<=a<=b<=n, such that (a+b)2+n2 is a square. https://oeis.org/A143714

最后,我们可以根据算法的特点,已知路线方案数,求解出最小的M的值。

3. Python 代码实现

Python 代码

import math
    
def get_num_of_cuboid_routes(M):
    number = 0
    for a in range(1, M+1):
        for b in range(1, a+1):        # b <= a
            for c in range(b, a+1):    # c <= b
                if True == check_integer_shortest_path(a, b, c):
                    number += 1
    return number

def get_num_of_cuboid_routes_new(M):
    number = 0
    for a in range(3, M+1):
        for bc in range(3, 2*a):
            if (bc*a) % 12 == 0:
                # check if it is an perfect square (integer)
                if not math.sqrt(bc*bc + a*a) % 1:    
                    number += min(bc, a+1) - (bc+1)//2    
    return number
        
def check_integer_shortest_path(a, b, c):
    '''
    After expanding a cube into a plane, SF distance may have three 
    kind of possiblilties, and we will get integer shortest path.  
    '''
    x, y, z = a*a+(b+c)*(b+c), b*b+(a+c)*(a+c), c*c+(a+b)*(a+b)
    x = min(x, y, z)
    if math.sqrt(x) % 1 == 0:
        return True
    return False
        
def find_least_value_of_M(max_num_of_solutions):
    '''
    A143714 Number of pairs (a,b), 1<=a<=b<=n, such that (a+b)^2+n^2 is a square.
    https://oeis.org/A143714
    '''
    number, a = 0, 2
        
    while number < max_num_of_solutions:
        a += 1
        for bc in range(3, 2*a):
            if (bc*a) % 12 == 0:
                # check if it is an perfect square (integer)
                if not math.sqrt(bc*bc + a*a) % 1:    
                    number += min(bc, a+1) - (bc+1)//2
    return a

def main():
    assert 2060 == get_num_of_cuboid_routes(100)
    assert 1975 == get_num_of_cuboid_routes_new(99)
    
    assert 100 == find_least_value_of_M(2060)
    assert 99  == find_least_value_of_M(1975)

    print("The least value of M which first exceeds one million solutions is %d." 
          % find_least_value_of_M(10**6))

if  __name__ == '__main__':
    main()

4. C++ 代码实现

C++代码

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cassert>
    
using namespace std;

class PE0086
{
private:
    bool check_perfect_square_integer(int x);
    bool check_integer_shortest_path(int a, int b, int c);

public:
    int get_num_of_cuboid_routes(int M);
    int get_num_of_cuboid_routes_new(int M);

    int find_least_value_of_M(int max_num_of_solutions);
};

bool PE0086::check_perfect_square_integer(int x)
{
    int root = (int)sqrt((double)x);
    if (x == root*root)
    {
        return true;
    }

    return false;
}

// After expanding a cube into a plane, SF distance may have three
// kind of possiblilties, and we will get integer shortest path.
bool PE0086::check_integer_shortest_path(int a, int b, int c)
{
    int x = a * a + (b + c)*(b + c);
    int y = b * b + (a + c)*(a + c);
    int z = c * c + (a + b)*(a + b);

    int m = min(x, min(y, z));

    return check_perfect_square_integer(m);
}

int PE0086::get_num_of_cuboid_routes(int M)
{
    int number = 0;

    for (int a = 1; a <= M; a++)
    {
        for (int b = 1; b <= a; b++) // b <= a 
        {
            for (int c = b; c <= a; c++) // c <= b
            {
                if (true == check_integer_shortest_path(a, b, c))
                {
                    number += 1;
                }
            }
        }
    }
    return number;
}

int PE0086::get_num_of_cuboid_routes_new(int M)
{
    int number = 0;

    for (int a = 3; a <= M; a++)
    {
        for (int bc = 3; bc <= 2 * a; bc++)
        {
            if ((bc*a) % 12 == 0)
            {
                // check if it is an perfect square(integer)
                if (true == check_perfect_square_integer(bc*bc + a * a))
                {
                    number += min(bc, a + 1) - (bc + 1) / 2;
                }
            }
        }
    }
    return number;
}
    
// A143714 Number of pairs(a, b), 1 <= a <= b <= n, 
// such that(a + b) ^ 2 + n ^ 2 is a square.
// https://oeis.org/A143714
int PE0086::find_least_value_of_M(int max_num_of_solutions)
{
    int number = 0;
    int a = 2;

    while (number < max_num_of_solutions)
    {
        a++;
        for (int bc = 3; bc <= 2 * a; bc++)
        {
            if ((bc*a) % 12 == 0)
            {
                // check if it is an perfect square(integer)
                if (true == check_perfect_square_integer(bc*bc + a*a))
                {
                    number += min(bc, a + 1) - (bc + 1) / 2;
                }
            }
        }
    }
    return a;
}

int main()
{
    PE0086 pe0086;
    
    int num_of_cuboid_routes = pe0086.get_num_of_cuboid_routes(100);
    assert(2060 == num_of_cuboid_routes);

    num_of_cuboid_routes = pe0086.get_num_of_cuboid_routes_new(99);
    assert(1975 == num_of_cuboid_routes);

    cout << "The least value of M which first exceeds one million solutions is ";
    cout << pe0086.find_least_value_of_M(1000000) << "." << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值