正在学习方老师的课程,打算边学习边写一个系列的博客,从python的基础练习到深度学习,方老师的教学非常仔细,在此表示感激。也希望通过此次学习让自己编程水平更上一层楼,不辜负自己,也不辜负老师的耐心教导——2021.2.6


目录

  • 1、5猴分桃问题
  • 2、翻扑克牌问题
  • 3、100阶乘,进阶
  • 4、囚犯放风问题
  • 5、猜姓名游戏


1、5猴分桃问题

题目:

python基础算法书 python基础算法题_逆向思维

代码:

def getPeaches(monkeys):
    unit = 1
    while True:
        ok,peaches = divide((monkeys-1)*unit,monkeys)
        if ok:
            return peaches
        unit +=1

def divide(peaches,monkeys):
    for _ in range(monkeys):
        if(peaches % (monkeys-1)==0):
            peaches = peaches//(monkeys-1)*monkeys + 1
        else:
            return False,0
    return True, peaches

2、翻扑克牌问题

题目:

1、有一幅只有点数没有花色的扑克牌,点数分别是1,2,3,…,20,一共20张。
2、我们把所有牌正面朝下堆成一叠放在手上,然后用另一只手翻开第一张,发现是1点。我们把这张1点牌放在一边,然后再摸下一张牌。这时我们并不看它的点数,而是把它放在这叠牌的末尾,使之成为最后一张。
3、接着,我们翻开下一张牌,发现是2点。我们把这张2点牌也放在一边,然后按顺序摸两张牌,不看点数,而是把它们放在这叠牌的末尾。
注意:是把它们一起放在末尾还是把他们一张一张按顺序放在末尾的结果是一样的。
再翻开下一张牌,发现是3.这张3点牌也被放在一边,我们再一张一张地摸3张牌,并按顺序放在末尾…以此类推,直到把所有牌都翻开并放在了一边。检查被翻开的牌的点数,发现按顺序分别是1、2、3、。。。、20
问:最初牌的顺序是什么?

代码:

#逆向思维程序========================================
def get_pokes(num):
    result = [num]
    p = num -1
    while p>0:
        insert(p,result)
        p -=1
    return result

def insert(p,result):
    for _ in range(p):
        last = result[-1]
        del result[-1]
        result.insert(0,last)
    result.insert(0,p)
print("逆向思维:\n")
print(get_pokes(20))


#
def get_pokesV2(num):
    result = [0]* num
    loc = [e for e in range(num)]
    for p in range(1,num):
        move(p,result,loc)
    result[loc[0]] = num
    return result

def move(p,result,loc):
    first = loc[0]
    del loc[0]
    result[first] = p
    for _ in range(p):
        first = loc[0]
        del loc[0]
        loc.append(first)

print("正向思维:\n")
print(get_pokesV2(20))

3、100阶乘,进阶

题目:

100的阶乘可以写作如下表达式:
100! = 1*2*3*....*98*99*100
这个如果用python一般的写法很简单就可以写出来,代码如下:

def GetFac(num):
    result = 1
    for i in range(1,num+1):
        result = result*i
    return result
 print('%d! = %d ' % (100,GetFac(100)))

结果:

python基础算法书 python基础算法题_逆向思维_02


可以看到结果是个很大的数字,如果用C/C++语言编写的时候很容易出现内存溢出,而导致无法求解的问题。

问题:

现在用python模拟如果限定最大数的情况下,计算并将其输出结果,用这个思路用C/C++写一个程序计算100阶乘。

解题思路:

1、将计算的结果每一位都放在list中,每一位的计算方法是相乘的结果加上进位

2、最后将list中的结果拼接为字符串输出结果

所以核心问题在于如何将多位数相乘的结果装到list中,这里采用分位乘法,记住进的位数,和乘法取余的结果进行保留。

python代码

def fac(n):
    result = [1]
    while n > 1:
        print("n=%d,result=%s"%(n,result))
        mul(result,n)#依次取出要乘的数字,将结果计算出来
        n -=1
    return to_str(result)

def mul(result,n):
    add = 0#进位
    for i in range(len(result)):
        r = n *result[i] + add
        result[i] = r %10
        add = r //10
    while add > 0:
        result.append(add%10)#如果进位超过了10则反复取余数放进列表中
        add //= 10#最后取出整数值
        
def to_str(list):#将列表连接起来,第一个是个位、第二个是十位...
    s = ''
    for i in list:
        s = str(i)+s
    return s

print('%d! = %s ' % (100,fac(100)))

4、囚犯放风问题

题目:

一群囚犯即将被带到牢房坐牢,看守把他们集中在一起,宣布:
1、每个囚犯将被单独关在一个牢房里;
2、每天会随机地抽取一名囚犯放风;
3、放风的地方有一盏电灯,囚犯可以任意开关这盏电灯;
4、电灯永久有电,永远不会损坏;
5、囚犯在防风的地方以及来回的路上都不会被其他囚犯看见;
6、牢房相互之间隔绝,囚犯相互之间不可能传递任何消息;
7、囚犯在放风时出了开关电灯不能留下任何痕迹或者信息;
8、看守只负责随机抽取囚犯,不会帮助囚犯传递信息;
9、如果有人确定所有人都被放风过,可以通知看守,看守确认之后可以把所有囚犯释放。如果永远没有人通知,或者通知的人弄错了(并不是所有人都被防风过),则所有人将永久坐牢,永无出头之日;
10、囚犯们可以商议一个方法出来以便避免永久坐牢。商议好之后就会被关进各自的牢房
我们的问题时:囚犯们会商议出什么办法?

解题思路:

1、推荐一个囚犯作为计数员,他看到灯亮着就灭掉灯,并且计数加1;
2、其他所有人是普通囚犯,看到等亮了就不管,灯灭了就点亮它。同时自己点亮过就不要再点亮,否则会出现重复的;
3、一直循环,如果总囚犯数是N,当计数员的计数等于N-1的时候就跳出循环(因为计数员可以计数说明)
python代码

import random#随机数生成包

def solve_prisons(num):
    counter = num -1 #一个主囚犯,负责计数
    print("计数员ID:%d\n"%(counter))
    turn_ons = [False]*(num - 1)
    lamp = False#灯的状态
    count = 0#计数
    while True:
        lucky = random.randint(0,num-1)#random.randint第二个参数是包含随机生成在内的,但是在numpy中np.random.randint第二个参数是不包含随机生成的
        lamp ,count = get_free(lucky,counter,turn_ons,lamp,count)
        if count == num - 1:
            break

def get_free(lucky,counter,turn_ons,lamp,count):#放风函数
    if lucky == counter:
        if lamp:
            lamp = False
            count +=1
    else:
        if not lamp and not turn_ons[lucky]:
            lamp = True
            turn_ons[lucky] = True
    print('lucky = %d,lamp = %s,count = %d,turn_ons:%s' %(lucky,lamp,count,turn_ons))
    return lamp,count
print("方案1:\n")
solve_prisons(4)

5、猜姓名游戏

一个算命先生,给几个姓名卡片(假设你的姓名就在卡片里存在)让你判别你的名字在不在卡片里面,就可以准确的说出你的姓氏,请想一想为什么,用程序模拟一下。

import math

def guess_name():
    names = '赵钱孙李周吴郑王冯程储卫姜武韩万祝董刘田汪'
    lines = get_lines(names)
    while True:
        answers = []  # 用户输入
        for line in lines:
            print(', '.join(line))
            answer = input('Is your name in this line?(y/n)')
            answer = 1 if answer in ('y','Y')else 0
            answers.append(answer)
        name = get_name(answers,names)
        print('Yor name is :',name)
        answer = input('Is continu guess name?(y/n)')
        if answer not in ('y','Y'):
            break



def get_lines(names):
    rows = int(math.log2(len(names)))+1
    lines = [[] for _ in range(rows)]
    for i,name in enumerate(names):
        id = i+1
        for j in range(rows):
            if id%2 == 1:
                lines[j].append(name)
            id //=2
    return lines


def get_name(answers,names):
    id = 0
    for digit in reversed(answers):#reversed反转列表
        id = id *2 +digit
    return "不存在的姓名" if id ==0 else names[id - 1]


guess_name()