这篇文章是最近几天看李永乐老师的《从一到无穷大》读书专栏而想到的一篇文章。在第一章 「做做数学游戏」 的简单数学,以及第二章 「空间、时间和爱因斯坦」 的拓扑学中(其实也是因为李老师目前只更新了这么多  ̄□ ̄||)有很多问题是可以通过计算机思维来思考的。所以这篇我将从计算机程序的角度来讨论《从一到无穷大》有趣的知识。

这篇文章会从科普数学角度以及程序解决问题的角度来讨论这些问题。

当然,如果你对自然科学感兴趣,并且也想观看李老师的专栏,在文章的末尾会有分享码。你可以通过我的分享来购买这门课程,我将佣金(目前是 29 元)全部返还给你。再次声明,我和荔枝微课平台没有任何合作,返还佣金只是为了给粉丝一些福利,交个朋友

Eratosthenes 素数筛法

原文摘录:有没有什么简单的办法能够将所有的质数按照顺序一个不漏的列出来呢?古希腊哲学家暨数学家 Eratosthenes 首次提出了这个问题,我们称之为埃氏筛法

算法讲述

Eratosthenes 画像

其实在之前的「快速素数筛法」一文中已经介绍过。当我们需要判断快速得到一张素数表,我们可以通过素数的基本定义来解决这个问题。

素数(Prime Number),也叫质数,指在大于 1 的自然数中,除了 1 和它本身以外,无法被其他自然数整除的数。

根据描述,为了筛选出素数,我们可以直接写出暴力代码:

import math
import time
primes = [0] * 100000start = time.time()
for i in range (2, len(primes)):flag = True# 只需要检查小于等于 sqrt(n) 的因数就可以了# 因为大于的那部分一定对应着一个小于 sqrt(n) 的因数for j in range(2, int(math.sqrt(i)) + 1):if 0 == i % j:flag = Falsebreakif flag:primes[i] = 1
end = time.time()
print(f'总耗时 {end - start}') # 总耗时 0.312835693359375print(primes[3]) # 1
print(primes[4]) # 0
print(primes[11]) # 1

这是我们正向的考虑这个数学问题。下面我们从计算机的一大思想 —— 缓存 来想这个问题。当我们计算  的时候,此时如果我们变换一个因子, 这个数其实也变相的刨除了。

所以,如果我们用缓存策略来考虑这个问题,由于 2 是一个质数,那么所有 2 的倍数都不是质数!我们按照这个规律依次对后面的数做一个排除,就可以找到所有质数了。再次放上这张过程图,在阅读代码之前先大概了解下筛选流程,有助于你来理解代码:

Eratosthenes 素数筛法过程
primes = [1] * 100000start = time.time()
primes[0] = primes[1] = 0for i in range(2, len(primes)):if primes[i] == 1:for j in range(2, len(primes)):if i * j >= len(primes):breakprimes[i * j] = 0end = time.time()
print(f'总耗时 {end - start}') # 总耗时 0.0969996452331543print(primes[3]) # 1
print(primes[4]) # 0
print(primes[11]) # 1

复杂度分析

根据上述算法介绍,可以看出:当外层循环是 i 时,内层循环一共执行了  次。因此总的时间消耗为:

其中  表示不超过 n 的素数个数。根据 素数定理[1] 有以下等式:

根据文献 「Villarino, Mark B, Mertens' Proof of Mertens' Theorem」[2],可知 Mertens 定理 2(下图为为文献中的定理引用部分):

Mertens 定理 2

根据大 O 的无穷大渐进的估算方法,得到算法复杂度:

所以我们了解到 Eratosthenes 素数筛法将普通的  的暴力筛选法优化到了  级别。

哥德巴赫猜想

原文摘录:数论中还有一个既没被证明也没被伪证的有趣问题,人称「哥德巴赫猜想」(Goldbach conjecture)。这个猜想是在 1742 年被提出的,它宣称任何一个偶数都能表示为两个质数之和。

哥德巴赫猜想举例图示

虽然我们现在也无法给出证明,但是由于我们学了上面的 Eratosthenes 素数筛选方法,则可以使用暴力大法来简单的验证一下哥德巴赫猜想。

import mathprimes = [1] * 100000000primes[0] = primes[1] = 0for i in range(2, len(primes)):if primes[i] == 1:for j in range(2, len(primes)):if (i * j) >= len(primes):breakprimes[i * j] = 0def goldbach_check(n: int):for k in range(2, 10000000 // 2):if primes[k] == 1 and primes[n - k] == 1:return (k, n - k)return Noneprint(goldbach_check(16)) # 3, 13
print(goldbach_check(6398)) # 19, 6379
print(goldbach_check(7479634)) # 3, 7479631

也许你会问道:即使我们证明了哥德巴赫猜想,到底有什么实际的应用呢?我身为一个程序员会告诉你目前看上去完全没有什么用处。但或许当千百年后,哥德巴赫猜想或者证明哥德巴赫猜想的方法将会是某个重要理论的根基,而这个重要的理论也许将会改变整个世界。

古希腊几何学家阿波罗尼乌斯总结了圆锥曲线理论,在当时那个时代也饱受争议。但是在一千八百年后德国天文学家开普勒将其用于行星轨道理论,并提出了开普勒三大定律。何夕的《伤心者》当中说道:“世界沉默着,为了这些伤心的名字,为了这些伤心的名字后面那千百年的寂寞时光。”

四色定理

原文摘录:假设有一个划分为若干区域的球面,现在我们要给球面上色,使得任意两个相邻区域(即拥有共同边界的区域)的颜色各不相同。要完成这个任务,我们需要几种不同的颜色?(答案是四种,这也就是四色定理的问题模型)

使用四色定理填充世界版图

关于四色定理的证明,其实是一个很好玩的故事。1976 年,数学家 Kenneth Appel 和 Wolfgang Haken 借助计算机首次将四色问题证明,四色问题也由此变成了四色定理。四色定理也是图论和拓扑学中的问题的抽象,所以使用编程来描述是十分合适的。

为了通过编程思维来了解四色定理,这里引入一个题目我们一起来思考一下解法。「POJ 1129 Channel Allocation」[3]题目描述大概意思是我们给出一个图来描述各个节点关系,然后我们用多种颜色给这个图染色,要求是相邻节点不能染成相同的颜色。解释一组样例:

Input:
4
A:BC
B:ACD
C:ABD
D:BCOutput:
3 channels needed.

样例示意

这种情况,我们使用如图三种颜色进行图染色,就可以满足题目要求。

这道题其实我们知道,可以用深度优先搜索来完成这个染色尝试。我们简单来实现一下:

n = 4input_demo = """A:BC
B:ACD
C:ABD
D:BC
"""G = [[] for _ in range(n)]
mark = [0] * n
ans = 4 # 根据四色定理,我们得知 ans 最大值就是 4datas = input_demo.split("\n")for line in datas:if len(line) == 0:continuef = ord(line[0]) - ord('A')for to_ch in line[2:]:t = ord(to_ch) - ord('A')G[f].append(t)def check(x: int, col: int) -> bool:global G, ans, markif mark[x] != 0:return Falsefor i in G[x]:if mark[i] == col:return Falsereturn Truedef dfs(pos: int):global G, ans, markif pos == n:ans = min(ans, max(mark))return for i in G[pos]:# 根据四色定理,仅需要使用 4 个颜色来染下一步即可for col in range(1, 5):if check(i, col):mark[i] = coldfs(i + 1)mark[0] = 1
dfs(1)print(mark) # 染色方法 [1, 3, 2, 1]
print(ans) # 需要颜色 3

当我们知道了四色定理这个结论,这道题其实就 在结果上已经做出了大幅度减枝

当然四色定理的我们可以进而将其抽象,他还可以利用在排程和分配问题上。例如我手上的几个任务,他们某几个之间存在互斥性,我需要对其进行排期。这时候我对日程来建立图,就可以求得排期方式。图论最神奇的地方,就是它可以将各种各样的模型转换成拓扑图的关系问题,再通过图算法从而高效的得到问题的答案

总结

很多科学读物中,都有很多知识都可以使用计算机思维来思考。程序就是我们解决问题的工具,在使用这个工具来解决问题的同时,也可以让我们收获更多编程经验和解决问题的能力。利用结论定理也可以大幅度的缩减算法复杂度,从而让算法性能得以最大的提升。

希望这篇文章可以对身为程序员的你也有所启发。


推广链接(并无合作)

参考资料

[1]

素数定理: https://zhuanlan.zhihu.com/p/37297929

[2]

「Villarino, Mark B, Mertens' Proof of Mertens' Theorem」: https://www.researchgate.net/publication/2119159_Mertens'_Proof_of_Mertens'_Theorem

[3]

「POJ 1129 Channel Allocation」: http://poj.org/problem?id=1129

《从一到无穷大》中的程序思维相关推荐

  1. 毕业两年的我--奋斗中的程序员

    又到一年毕业季,不知不觉,自己毕业快两年了,在这两年中,从一位小白程序员蜕化到现在的拥有两年经验的C++程序员,这两年里面,不敢说成长有多快,进步有多大,但是感觉很踏实,每天都过得很充实,每天都在一点 ...

  2. 谈谈如何在面试中发掘程序猿的核心竞争力 什么是程序员的核心竞争力?

    谈谈如何在面试中发掘程序猿的核心竞争力 早两天看了知乎日报的这篇文章<什么是程序员的核心竞争力?>,caoz讲的几点是让我感同身受.这让我联想起了给程序猿的面试,其实也就是通过短暂的接触来 ...

  3. 辩证思维在计算机中的应用,浅论计算机科学技术应用中的辩证思维.doc

    浅论计算机科学技术应用中的辩证思维 精品论文 参考文献 浅论计算机科学技术应用中的辩证思维 王 琦(潍坊科技学院 山东 潍坊 262700)摘 要:在计算机科学技术的应用中常常遇到许多矛盾和问题,本文 ...

  4. C#中Winform程序中如何实现多维表头【不通过第三方报表程序】

    问题:C#中Winform程序中如何实现多维表头. 在网上搜了很多方法,大多数方法对于我这种新手,看的都不是很懂.最后在新浪博客看到了一篇比较易懂的文章:[DataGridView二维表头与合并单元格 ...

  5. android中存放程序资源,Android 工程中存放各种程序资源的目录是()

    摘要: 工各种模型按照空间框架.片厚的垫度_要求两侧,资源轴承间隙垫片调整利用时.工各种Z系定位产品列的是(.... 工各种模型按照空间框架. 的要的求是错误,程中存放程序隙时轴承的轴采用承间压铅量主 ...

  6. EXE文件中的程序的加载过程 SA是什么呢?PSP是什么?

    精华解读:https://zhidao.baidu.com/question/195901151.html 段地址SA,默认在DS中! 查看PSP命令: -d ds:0 一般来说,PSP是256个字节 ...

  7. 中美程序员的不完全对比,看看跟你了解的一样吗?

    大家好,我是DD. 你平时有想过这个问题吗?为什么一些在国外流行的技术和框架,在国内就很少被认可呢?是技术的原因还是人的原因呢? 今天刚好在知乎上看到一篇国内外程序员区别对比的文章,原文作者是知乎的一 ...

  8. stm32f4 RAM中运行程序 读保护设置

    主要是为了在RAM中运行程序来解除读保护的.没想到ST-Link Utility 就直接可以. ST-Link Utility:target-->options bytes-->就可以看到 ...

  9. iOS 中捕获程序崩溃日志

    iOS开发中遇到程序崩溃是很正常的事情,如何在程序崩溃时捕获到异常信息并通知开发者,是大多数软件都选择的方法.下面就介绍如何在iOS中实现: 1. 在程序启动时加上一个异常捕获监听,用来处理程序崩溃时 ...

最新文章

  1. Run application
  2. Spring-AOP动态代理技术(底层代码)
  3. 24.volatile关键字的作用、volatile原理、可见性、内存屏障、volatile性能、transient
  4. 小程序 获取当前用户地址及地图显示
  5. 图片夹_各种变调夹的优缺点、原理和使用方法
  6. php生成图片水印,PHP生成图片加文字及图案水印办法
  7. Python小白的数学建模课-A1.国赛赛题类型分析
  8. java PreparedStatement和statement的区别
  9. 3DMAX安装包及近百GB素材资源,以及3D游戏建模教程
  10. GDC2017分享:移动VR开发者的赚钱之道
  11. 6-3cifar10数据集介绍-读取-处理
  12. 礼遇双十二,送12份福利好事成双
  13. matla可以导出回归结果表格吗_表格高级筛选,一键筛出想要的数据
  14. PHP学习笔记二(面向对象和表单)
  15. 来了!微信小程序五款最受欢迎的UI框架解读
  16. 【编程菜谱系列一】手把手教你用废旧手机改造为人脸识别监控
  17. 双系统卸载ubuntu后开机进入grub界面的解决方案
  18. PostgreSQL获得去、今、明年份、今年的第一天、去年的第一天转换时区、最后一天等
  19. 优矿-python计算上证50之间的相关系数
  20. mysql三叶草,温州日报瓯网 - 面对温州话,你被困住了吗?

热门文章

  1. 百度地图聚合中的marker添加label后移动、放大缩小时label消失的问题download
  2. ONEROOT获得Bithumb大股东BXA战略投资,成为区块链行业准独角兽
  3. 05-kubernetes Pod控制器应用进阶
  4. 谷歌浏览器无法翻译中文解决办法
  5. flowable中BPM实现核心对象
  6. stm32 CANOpen
  7. 项目 cg day06
  8. 2020最新微信棋牌游戏H5域名防封的解决方案
  9. oracle 口令修改,Oracle更改口令
  10. 技术的发展与互联网的发展