实验三大步骤:一立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为一个正整数。请问会杀到几号?
下为输出的结果: