编程任务|随机摆放的刀叉开始认识数学思维

任务源自旧版的Brilliant数学讨论问题。2019-09-02我曾经发布过,可惜已经下线,幸活大喵做足备份。

该问题看似是概率问题,实则不然。

官方给出的解法透露出一个非常重要的数学思维方法:

数学语言 —— 为何以及如何构造一个函数 f(n);

运用恰当构造的函数为逻辑推理的起点;

Python随机模块模拟验证之;

先从关键词开始——常用英文短语:

consecutive:连续 如1,2,3,4

in the line-up:排成一列

“There's a randomly ordered line of 15 forks and 15 spoons on the counter. Chef Nidhi only needs 5 forks and 5 spoons.Can she always pick up exactly what she needs by selecting 10 consecutive utensils starting from somewhere in the line-up?

编程任务|随机摆放的刀叉开始认识数学思维_第1张图片

图片

15把叉子和15把勺子随机摆放的,图为示例

题目考察数学思维:

丁丁猫一家的厨房有30付餐具,包含15个叉子和15把刀。丁大喵说了,叉子和勺子的摆放要方便拿取,家里5个人吃饭,桌子上需要摆放5付刀叉,取餐具的时候,很方便地找出5把叉子和5把刀。

一家之主的丁老喵让孩子们想想,该怎么摆放?

丁小喵抢先发话:“每次刷碗后,叉子和勺子要分开摆放”

“不需要” 丁大喵说:"不必这么麻烦,经常有不自觉的取走不按规则放回去,

“ 无论刀叉怎样摆放顺序,都可以找到10个连续摆放的餐具,恰好满足有5个叉子和5个勺子!”

哦?真的可以做到吗?

丁大喵说的是真的吗?

任务场景之二

学校举办新学期的运动会,首先班级推荐10个旗手,要有5男生和5个女生组成方阵,走在班级队伍的最前面,要求10人的身高要尽量接近。

班里共有30人其中15个男生和15个女生。老师先按身高排出30人有高到低排出顺序。请问应该如何选出 5 对男女生推荐为旗手方阵的人选。

——似乎和刀叉的摆放有异曲同工之妙!

逻辑推理的思路梳理:

将30个餐具分成 20个连续的组。最左边开始选10个,即1到10为第1组,2-11为第2组,... 第20-30为第20组 —— 分组是整个思路的关键!!

设一个函数f(n)返回一组器具中叉的数量—— 数学语言描述

该函数显然是连续的,满足:

(1)因为两个连续组的叉的数目之间的差不能大于1。

考虑30把厨具里必然有15把叉子,那么下面必然成立

f(1)+f(10)+f(20) = 15

再看 f(1),f(10),f(20) 3个组中有没有等于5的,如果有,就是我们要找的那一组。如果没有,这三个函数的返回值必然要满足:

(2)至少一个必须大于5,其中一个小于5。

然后,如上所述函数返回值必然满足(1),(2),那么存在某个f(n),n不在1,10,20之间,但f(n)必然是小于5和大于5之间某个数,连续变化的数列中:

譬如3,4,5,6,7之间,可见,由于满足下面两个条件,必然存在某个n,f(n)的返回值恰好为5!

(1)两个连续组的叉的数目之间的差不能大于1

(2)至少一个必须大于5,其中一个小于5

丁小喵说:

“总觉的不踏实,能不能验证下呢?

怎么验证呢

... ...

丁大喵提醒小喵,你这学期学python了

试试python可以啊?!

编程任务|随机摆放的刀叉开始认识数学思维_第2张图片

编程时刻开始 ...

叉子表达为1,勺子表达为0

随机生成一个只有0,1的数列

... ...

import random
from collections import Counter
while True:
    group = [random.randint(0, 1) for i in range(30)]   
    #叉子为1,勺子为0,随机数量生成数组group
    num_fork = str(group).count("1")
    num_spoon = str(group).count("0")
    if num_fork == 15 and num_spoon ==15:
        print(group)
        print(Counter(group))
        break
j = 0
while True:
    #print('随机顺序摆放的叉子和勺子:',group[j:j+10])
    fork = str((group[j:j+10])).count("1")
    spoon = str(group[j:j+10]).count("0")
    if fork == 5 and spoon == 5:
        print ('j =',j)
        print (group[j:j+10])
        break
    j += 1

生成刀叉的随机摆放顺序:

[1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 
1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 
0, 1, 1, 1, 1, 0, 0, 1, 0, 0]

保证刀叉各有15把:

Counter({1: 15, 0: 15})

j = 4

[0, 0, 1, 0, 0, 1, 1, 1, 0, 1]

解读:j =4 就是数列第5个数开始算起,10个连续厨具恰好满足5个叉子和5个勺子

时至今日,再看该任务依然启发力道十足!看能否再做些改进,也只能在随机生成函数的代码做些精简而已。

如何精简?

  1. 构造一个随机数列包含15个 1(folk)和 15个 0 (spoon)
  2. 长度为 30 的数组,包含30个 0
  3. 随机生成 15个数为0-29之间的地址脚标
random_index = [random.randint(0,29) for _ in range(30)]

print('random_index =',len(random_index),random_index)

random_index = 30 [13, 22, 4, 21, 7, 27, 2, 1, 27, 6, 
15, 20, 26, 22, 24, 29, 22, 29, 2, 4, 11, 2, 13, 27, 
2, 25, 28, 10, 23, 0]

显然有重复的值,不可取。不过可以去重操作完善之。 数组求和结果为15则验证随机数组符合要求。

def randomIndex(n):
    cunt,inbox = 0,[]
    init = [0] * n
    while sum(init) < n//2:
        #循环终止条件是恰好一半的元素值为 1
        idx = random.randint(0,29)
        if idx not in inbox: #地址去重
            inbox.append(idx)
            init[idx] = 1
        else:pass
        cunt += 1
    return init,sum(init)
    
n = 30
print(randomIndex(n))

([0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 
0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1], 15)

以上输出的随机数组满足要求!

def check(s,l):
    for i in range(len(s)-l):        
        if s[i:i+l].count(0) == s[i:i+l].count(1):
            return s[i:i+l],i
    else:return None

s = [1, 1, 0, 1, 1, 1, 1, 1, 0, 
     1, 1, 0, 0, 1, 1, 0, 1, 0, 0,
     1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0]
     
l = 10

print(check(seq,l))
([0, 1, 1, 0, 0, 1, 1, 0, 1, 0], 8)

第 8 个元素开始连续 10 个恰好包含 5个叉和5个勺。

课程设计:丁丁猫亲子创客

本节课两个任务场景激发编程的动力,适于小学6年级以上的孩子;

锻炼孩子遇到实际场景需求,先抽象为可用编程实现的思维过程;

熟悉并使用python数组的切片、数组元素统计函数使用;

使用英文描述和理解问题需求,掌握两个math里常见的单词 consecutive in the line-up

理解f(n)函数的本质,用函数描述问题的好习惯;

本文由 mdnice 多平台发布

你可能感兴趣的:(后端)