zoukankan      html  css  js  c++  java
  • 用欧拉计划学Rust编程(第61题)

    由于研究Libra等数字货币编程技术的需要,学习了一段时间的Rust编程,一不小心刷题上瘾。我把解决63道问题的过程记录了下来,写成了一本《用欧拉计划学 Rust 编程》PDF电子书,请随意下载。

    链接:https://pan.baidu.com/s/1NRfTwAcUFH-QS8jMwo6pqw

    提取码:qfha

    “欧拉计划”的网址:
    https://projecteuler.net

    英文如果不过关,可以到中文翻译的网站:
    http://pe-cn.github.io/

    这个网站提供了几百道由易到难的数学问题,你可以用任何办法去解决它,当然主要还得靠编程,编程语言不限,论坛里已经有Java、C#、Python、Lisp、Haskell等各种解法,当然如果你直接用google搜索答案就没任何乐趣了。

    这次解答的是第61题:

    https://projecteuler.net/problem=61

    题目描述:

    循环的多边形数

    三角形数、正方形数、五边形数、六边形数、七边形数和八边形数统称为多边形数。它们分别由如下的公式给出:

    三角形数 P3,n=n(n+1)/2 1, 3, 6, 10, 15, …
    正方形数 P4,n=n2 1, 4, 9, 16, 25, …
    五边形数 P5,n=n(3n−1)/2 1, 5, 12, 22, 35, …
    六边形数 P6,n=n(2n−1) 1, 6, 15, 28, 45, …
    七边形数 P7,n=n(5n−3)/2 1, 7, 18, 34, 55, …
    八边形数 P8,n=n(3n−2) 1, 8, 21, 40, 65, …

    由三个4位数8128、2882、8281构成的有序集有如下三个有趣的性质。

    • 这个集合是循环的,每个数的后两位是后一个数的前两位(最后一个数的后两位也是第一个数的前两位)。
    • 每种多边形数——三角形数(P3,127=8128)、正方形数(P4,91=8281)和五边形数(P5,44=2882)——在其中各有一个代表。
    • 这是唯一一组满足上述性质的4位数有序集。

    存在唯一一个包含六个4位数的有序循环集,每种多边形数——三角形数、正方形数、五边形数、六边形数、七边形数和八边形数——在其中各有一个代表。求这个集合的元素和。

    解题过程:

    把复杂的问题分解为一个一个的简单问题。

    第一步: 先把所有四位数求出来

    利用map()、filter()和take_while()等函数,可以用一行语句将数组生成。

    let p3: Vec<u32> = (1..)
        .map(|n| n * (n + 1) / 2)
        .filter(|&n| n > 1000)
        .take_while(|&n| n <= 9999)
        .collect();
        
    let p4: Vec<u32> = (1..)
        .map(|n| n * n)
        .filter(|&n| n > 1000)
        .take_while(|&n| n <= 9999)
        .collect(); 
    

    如果这样生成六种多边形数,会有大量的重复代码,可以闭包作为函数的参数,统一写一个函数,这样代码非常简练。

    let p3 = gen_poly_numbers(1000, 9999, |n| n * (n + 1) / 2);
    let p4 = gen_poly_numbers(1000, 9999, |n| n * n);
    let p5 = gen_poly_numbers(1000, 9999, |n| n * (3 * n - 1) / 2);
    let p6 = gen_poly_numbers(1000, 9999, |n| n * (2 * n - 1));
    let p7 = gen_poly_numbers(1000, 9999, |n| n * (5 * n - 3) / 2);
    let p8 = gen_poly_numbers(1000, 9999, |n| n * (3 * n - 2));
     
    
    fn gen_poly_numbers(start: u32, end: u32, f: fn(u32) -> u32) -> Vec<u32> {
        (1..).map(f)
             .filter(|&n| n >= start)
             .take_while(|&n| n <= end)
             .collect()
    }
    

    这里的一个语法知识点是f: fn(u32) -> u32的写法,把一个函数作为参数传递给另一个函数。

    第二步: 递归算法

    现在仍不要直接奔向最后的问题,先从简单的情况入手,用题目中给出的三个多边形数[8128, 8281, 2882],实现一个递归算法,验证算法的正确性。

    算法描述:

    1)从p3中的取一个数 for n in p3

    2)假设这个数是8128,记录到found数组中,我们下一步的任务是从[p4, p5]数组中寻找28开头,81结尾的两个数,伪代码:find([p4, p5], 28, 81, [8128])

    3)先在p4中找,再在p5中找 for cur_list in lists

    4)在数组中寻找以28开头的数 for n in cur_list

    5)假设是在p5中找到了2882,此时found数组变为[8128, 2882],递归调用,在[p4]中查找以82开头,81结尾的一个数 find([p4], 82, 81, [8128, 2882])

    5.1)在p4里会找到一个以82开头的数,即8281,更新found,再调用 find([], 81, 81 [8128, 2882, 8281]

    5.2)从这里可以发现递归函数的退出机制,待查的数组已经为空,要找的开头与结尾正好相等。

    递归函数的源代码:

    fn find(lists: &[&[u32]], start: u32, end: u32, found: &[u32])  {
        if lists.is_empty() && start == end {
            let result = found.iter().sum::<u32>();
            println!("{:?} {}", found, result);
        }
    
        for (i, &cur_list) in lists.iter().enumerate() {
            for &n in cur_list {
                if head(n) == start {
                    let mut lists_copy = lists.to_vec();
                    lists_copy.remove(i);
                    let mut found_copy = found.to_vec();
                    found_copy.push(n);
                    find(&lists_copy, tail(n), end, &found_copy);
                }
            }
        }
    }
    

    lists.copy.remove(i)的含义,假设当前搜索的数组为[p4, p5, p6, p7, p8],如果在p5中找到了满足条件的数,后续的搜索范围将是[p4, p6, p7, p8],这里的i记住数组中的位置,remove(i)将删除p5。

    主程序中的代码:

    for n in p3 {
        find(&[&p4, &p5], n % 100, n / 100, &[n]);
    }
    

    第三步:解决最终的问题

    搜索3个数的代码测试通过后,再搜索6个数。

    for n in p3 {
        find(&[&p4, &p5, &p6, &p7, &p8], n % 100, n / 100, &[n]);
    }
    

    由于p8中的数据元素较少,先搜索p8可能会稍快一点。

    --- END ---

    我把解决这些问题的过程记录了下来,写成了一本《用欧拉计划学 Rust 编程》PDF电子书,请随意下载。

    链接:https://pan.baidu.com/s/1NRfTwAcUFH-QS8jMwo6pqw

    提取码:qfha

    由于欧拉计划不让发布100题之外的解题步骤,否则封号,所以最新PDF不再公开,请加我微信(SLOFSLB)索要最新的PDF电子书。

  • 相关阅读:
    js的基本数据类型有哪些?
    页面优化的方式有哪些?
    为什么要用rem
    sass开发过程中遇到的几个坑
    js事件监听
    js数组去重的方法
    什么是怪异盒模型
    Cookie SameSite属性介绍及其在ASP.NET项目中的应用
    HttpServlet在第一个Servlet程序中的知识点
    Myeclipse 2017 创建第一个servlet步骤
  • 原文地址:https://www.cnblogs.com/speeding/p/12530064.html
Copyright © 2011-2022 走看看