【实验课】一群人围一圈,隔一个杀一个,剩一个,最后活谁?

实验三大步骤:一立Flag,二百度,三动手,四发朋友圈。

初始问题

东罗马帝国,里奥二世曾今让64名死刑犯站成一个圈,隔一个杀一个,杀到剩下一个为止。并让所有死刑犯自己争抢位置,如果你是死刑犯的一员,你要挑什么位置呢?

对N问题


问题一般化:包含N个节点(节点编号1-N)的圆,隔一个节点从中摘除一个节点,直到只剩下一个节点为止。求剩下节点的编号。

问题特殊化:应当从N=1,...,10开始逐步研究起,以求得规律,此处改为一律用程序实现

代码如下:

#0=live 1=death
def f(n):
    li=[0]*n
    i=0
    death=0
    while True:
        #如果活的杀死他,并隔一个指向下一个位置
        if li[i]==0:
            li[i]=1
            death=death+1
            if death==n-1:
                break
            i=(i+2 if i+2<n else i+2-n) 
        #如果死的,不进行操作
        elif li[i]==1:
            i=(i+1 if i+1<n else i+1-n)
    for i in range(n):
        if li[i]==0:
            print(i+1)#0对应1
            return


for i in range(2,101):
    f(i)

结果如图:

 

猜测规律:N人参加的排队杀人游戏,如果N为偶数,存活者为N,如果为奇数,存活者为N-1。进一步升华总结到,队伍中最大的偶数角色会存活。

归纳法证明规律:

1.k=2,3时,存活者编号分别为2,2,符合规律

2.假设k=N时成立,首轮收割后,奇数者死去,偶数者的队尾仍旧在队尾。N->N-1有问题还,等待有志者协同证明

 

后日谈

半个月后重新看这个问题,我会给什么解答呢?

我先想了一下我曾经是如何解决这个问题的,我记得我先是在小时候(高中)看过这个问题,当时在脑子,用纸和笔疯狂的算。

对,高中就是使用纸和笔的巅峰。纸和笔,以及若干数学方法使得很多不可算之物变得可算。

后来接触了更加厉害的工具(计算机)之后,又一次我又重新看到了这个问题,这个问题是很容易编程解决的,且是适合编程,可以如此想想,这个问题重复性高,输入简单(只需要准备一定数量的人),过程复杂(交给计算机就好了)。

因而就开始编程解决这个问题。那时候我还是面向对象的俘虏,我先用了C#写了一个比较复杂的计算。当时甚至还向高中学生显摆来着(因为以高中的知识体系,是真的很难完成这个题目的)。后来那版C#代码遗失了。(代码遗失也是一个很重要的问题,当然这个重要主要是指心态上的)

后来有一天我上了一门慕课上的数学课,课程上讲了一种非常普世的方法即对N问题。其将问题拆成了如下基本步骤,1.问题特殊化。(怎样简单怎样来,先从N=0或者1开始,逐步套路问题,找到解决问题的办法)2.问题泛化。给出问题的对N定义。3.猜测规律4.归纳法证明规律。

这种思考问题的方法很强大,我思考能否使用这种方法来解决高中时代困扰我的问题。因而,又拿出纸和笔开始讨论起来了这个问题。很遗憾,这个强大的工具没能帮助我思辨地解决这个问题。因而,我又又又,考虑用程序语言实现之。这次用的是python代码,就是上边附上的那个代码,代码本身就优秀很多了。但理解起来还是比较抽象。

 

后来有一次室友ZX哥哥,向我讨要编程的学习经。我和他以此题作为思考编程的方法,和他进行了探讨。他懂得基本的循环迭代,但对于深刻的编程思想,却总有点不知所以。又做了一遍这个题目。为了和他讲清楚这个问题。(有需求就会有创新)我说总结了如下一番话语:

编程就是对生活问题的一种模拟。生活中怎么想,程序中就应该怎样想。

因而,我这次直接引入了一个新的概念,一百个赴死的勇士团,刀子。刀子每次会指向一个位置,把对应位置的勇士杀死,刀子每次会向后向移动X个位置。只计算活人的。

def kiil(killnum):
    #找一百个人过来送死
    persons=[1]*100
    knife_pos=0
    for i in range(99):
        #杀人行动
        persons[knife_pos]=0
        #数数行动
        num=0
        while num<killnum:
            knife_pos+=1
            if knife_pos>99:
                knife_pos=0
            if persons[knife_pos]==1:
                num+=1

    #找人
    for i in range(100):
        if persons[i]==1:
            # print("杀",killnum,"人时:第i个人活着:i=",i)
            return i
up=100
x=list(range(1,up+1))
y=[]
for i in range(1,up+1):
    y.append(kiil(i))

import matplotlib.pyplot as plt
# x=[1,2,3,4]
# y=[4,3,2,1]
plt.plot(x, y,color='r',markerfacecolor='blue',marker='o')
for a, b in zip(x, y):  
    plt.text(a, b, (a,b),ha='center', va='bottom', fontsize=10) 
plt.legend("kiil=dsa")
plt.title("kill")
plt.show()

看看这优秀的代码,多余的描述真的显得多余,你可以自己写一写这个问题:

东罗马帝国,里奥二世曾今让100名死刑犯站成一个圈,从第一位开始杀起,每X个杀一个,X为一个正整数。请问会杀到几号?

下为输出的结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值