Python基础(33)–经典练习题:百钱买百鸡、谁家孩子跑得最慢、杨辉三角

◎知识点

  1. 百钱买百鸡

  2. 谁家孩子跑得最慢

  3. 杨辉三角


◎脚本练习

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
 @FileName:    python_practice2.py
 @Function:    python practice
 @Author:      Zhihe An
 @Site:        https://chegva.com
 @Time:        2021/7/6
"""


"""一、百钱买百鸡"""

"""
【问题描述】
    用100文钱买100只鸡,其中公鸡5文钱1只,母鸡3文钱1只,小鸡1文钱3只
    求各买了几只公鸡、母鸡和小鸡
    
【设计思路】
    设计思路一:
    设公鸡、母鸡和小鸡的只数分别为x、y和z,根据问题描述可以得到如下方程组:
    x + y + z = 100
    5x + 3y + z/3 = 100
    
    如果100文钱全买公鸡,最多可买100 / 5 = 20只,所以x的取值范围是:[0, 20]
    如果100文钱全买母鸡,最多可买100 / 3 = 33只,所以y的取值范围是:[0, 33]
    如果100文钱全买小鸡,最多可买100 * 3 = 300只
    因为总共买了100只鸡,且1文钱3只,所以z的取值范围是:[0, 100],并且z能被3整除
    
    通过三重循环穷举x、y和z的值
    在穷举的过程中,只要x、y和z满足上面的方程组,则得到一组符合条件的解
"""

# 通过三重循环穷举x、y和z的值
# 如果100文钱全买公鸡,最多可买100 / 5 = 20只,所以x的取值范围是:[0, 20]
for x in range(21):
    # 如果100文钱全买母鸡,最多可买100 / 3 = 33只,所以y的取值范围是:[0, 33]
    for y in range(34):
        # 如果100文钱全买小鸡,最多可买100 * 3 = 300只
        # 因为总共买了100只鸡,且1文钱3只,所以z的取值范围是:[0, 100], 并且z能被3整除
        for z in range(0, 101, 3):
            if x + y + z == 100 and 5 * x + 3 * y + z / 3 == 100:
                print('公鸡的只数:%d,母鸡的只数:%d,小鸡的只数:%d' % (x, y, z))

"""
    设计思路二:
    通过二重循环穷举x和y的值
    在穷举的过程中,求出z = 100 - x - y
    只要z满足:z >= 0 且 z能被3整除 且 5x + 3y + z/3 = 100,则得到一组符合条件的解
"""

for x in range(21):
    for y in range(34):
        z = 100 - x - y
        if z >= 0 and z % 3 == 0 and 5 * x + 3 * y + z / 3 == 100:
            print('公鸡的只数:{},母鸡的只数:{},小鸡的只数:{}'.format(x, y, z))


"""二、谁家孩子跑得最慢"""

"""
【问题描述】
    张家、王家和李家各有三个孩子
    一天,三家的九个孩子在一起比赛跑步,规定:
    跑第一名得9分,跑第二名得8分,跑第三名得7分,...,跑第九名得1分
    
    比赛结果如下:
    (1) 各家三个孩子的总分相同
    (2) 第一名是李家的孩子,第二名是王家的孩子
    (3) 所有孩子的名次没有并列的
    (4) 各家三个孩子的名次都没有相连的
    求最后一名是谁家的孩子
    
【设计思路】
    由1可知:
    各家三个孩子的总分都是:(1+2+3+4+5+6+7+8+9)/3=15
    
    由2可知:
    因为第1名是李家的孩子,所以可设李家孩子的分数分别为:9、x、15-(9+x),即:9、x、6-x,其中,x的取值范围是[1, 5]
    因为第2名是王家的孩子,所以可设王家孩子的分数分别为:8、y、15-(8+y),即:8、y、7-y,其中,y的取值范围是[1, 6]
    
    由3和4可知:
    x-(6-x)>1,y-(7-y)>1
    
    通过循环穷举李家三个孩子的分数和王家三个孩子的分数
    在穷举的过程中,定义一个列表存放所有名次对应的分数
    每穷举一次李家三个孩子的分数,就把李家三个孩子的分数从列表中删除
    每穷举一次王家三个孩子的分数,就把王家三个孩子的分数从列表中删除
    列表中剩余的元素即为张家三个孩子的分数,从大到小分别为zhang[2]、zhang[1]、zhang[0]
    因为张家三个孩子的名次没有相连的
    所以zhang[2] - zhang[1] > 1,并且zhang[1] - zhang[0] > 1 
"""

def slowest_child():
    for li in [[9, x, 6 - x] for x in range(1, 6) if x - (6 - x) > 1]:
        # 在穷举的过程中,定义一个列表存放所有名次对应的分数
        scores = list(range(1, 10))
        # 每穷举一次李家三个孩子的分数,就把李家三个孩子的分数从列表中删除
        for score in li:
            scores.remove(score)

        for wang in [[8, y, 7 -y] for y in scores if 7 -y in scores and y - (7 - y) > 1]:
            for score in wang:
                scores.remove(score)

        # 列表中剩余的元素即为张家三个孩子的分数,从大到小分别为zhang[2]、zhang[1]、zhang[0]
        zhang = scores
        # 因为张家三个孩子的名次没有相连的
        # 所以zhang[2] - zhang[1] > 1,并且zhang[1] - zhang[0] > 1
        if zhang[2] - zhang[1] > 1 and zhang[1] - zhang[0] > 1:
            print('李家三个孩子的分数:', li)
            print('王家三个孩子的分数:', wang)
            print('张家三个孩子的分数:', zhang)

slowest_child()


"""三、杨辉三角"""

"""
【问题描述】
    打印下图所示的杨辉三角:
             1
       1 1
      1 2 1
     1 3 3 1
    1 4 6 4 1
   1 5 10 10 5 1
  1 6 15 20 15 6 1
 1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
......
【设计思路】
    杨辉三角的特点:
    (1) 第i行有i个数
    (2) 每行的第一个数和最后一个数都是1
    (3) 每行除了第一个数和最后一个数,其余各数都是其两肩上的数之和

如果将所有的数存在一个二维列表L中,则有:
[[1],
 [1, 1]
 [1, 2, 1]
 [1, 3, 3, 1]
 [1, 4, 6, 4, 1]
 [1, 5, 10, 10, 5, 1]
 [1, 6, 15, 20, 15, 6, 1]
 [1, 7, 21, 35, 35, 21, 7, 1]
 [1, 8, 28, 56, 70, 56, 28, 8, 1]]
 
假设要打印n行,对于特点2,则有:
L[i][0] = L[i][i] = 1(i =  0,1,2,...,n-1)
对于特点3,则有:
当j != 0 且 j != i时,L[i][j] = L[i-1][j-1] + L[i-1][j]

首先,初始化一个所有元素都为1的n行二维列表,第i行有i个数
然后,根据上述特点3的条件和公式更新二维列表,对杨辉三角中不为1的位置进行更新
最后,根据杨辉三角的格式打印二维列表
    打印每行的内容前,先打印一定数量的水平制表符,第i行打印n-i个
    打印每行的内容时,除最后一个数之外,每打印一个数之后打印两个水平制表符
    对于每行的最后一个数,打印之后换行,准备打印下一行
"""

# 首先,初始化一个所有元素都为1的n行二维列表,第i行有i个数
L = [[1 for j in range(i + 1)] for i in range(9)]

# 然后,对杨辉三角中不为1的位置进行更新
for i in range(2, 9):
    for j in range(i + 1):
        # 每行除了第一个数和最后一个数,其余各数都是其两肩上的数之和
        if j != 0 and j != i:
            L[i][j] = L[i - 1][j - 1] + L[i - 1][j]

# 最后,根据杨辉三角的格式打印二维列表
for i in range(9):
    # 打印每行的内容前,先打印一定数量的水平制表符,第i行打印n-i个
    print('\t' * (8 - i), end = '')

    # 打印每行的内容时
    for j in range(i + 1):
        # 除最后一个数之外
        if j != i:
            # 每打印一个数之后打印两个水平制表符
            print('%d\t\t' % L[i][j], end = '')
        # 对于每行的最后一个数
        else:
            # 打印之后换行,准备打印下一行
            print('%d' % L[i][j])

◎脚本地址:https://github.com/anzhihe/learning/blob/master/python/practise/learn-python/python_basic/python_practice2.py

anzhihe安志合个人博客,版权所有丨 如未注明,均为原创 丨转载请注明转自:https://chegva.com/4929.html | ☆★★每天进步一点点,加油!★★☆

您可能还感兴趣的文章!

发表评论

电子邮件地址不会被公开。 必填项已用*标注