4.4 综合案例解析

例4-8 输入若干个成绩,求所有成绩的平均分。每输入一个成绩后询问是否继续输入下一个成绩,回答“yes”就继续输入下一个成绩,回答“no”就停止输入成绩。

基本思路:使用循环结构+异常处理结构来保证用户输入的合法性。关于异常处理结构请参考第11章。

   1.  numbers = []
   2.  while True:
   3.      x = input(’请输入一个成绩:')
   4.      #异常处理结构,用来保证用户只能输入实数
   5.      try:
   6.         #先把x转换成实数,然后追加到列表numbers尾部
   7.         numbers.append(float(x))
   8.      except:
   9.         print(’不是合法成绩’)
  10.
  11.      #下面的循环用来限制用户只能输入任意大小写的“yes”或者“no”
  12.      while True:
  13.         flag = input(’继续输入吗?(yes/no)').lower()
  14.         if flag not in ('yes', 'no'):
  15.             print(’只能输入yes或no')
  16.         else:
  17.             break
  18.      if flag=='no':
  19.         break
  20.
  21.  #计算平均分
  22.  print(sum(numbers)/len(numbers))

例4-9 编写程序,判断今天是今年的第几天。

基本思路:先假设二月有28天,然后获取当前日期,如果是闰年再把二月改为29天。如果当前是一月,该月第几天也就是今年的第几天;如果不是一月,先把前面已经过完的所有整月天数加起来,再加上当月的第几天,就是今年的第几天。

   1.  import time
   2.
   3.  date = time.localtime()                            #获取当前日期时间
   4.  year, month, day = date[:3]                        #获取年、月、日信息
   5.  day_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
   6.                                                      #一年中每个月的天数
   7.  if year%400==0 or (year%4==0 and year%100! =0):     #判断是否为闰年
   8.      day_month[1] = 29                               #闰年的2月是29天
   9.  if month==1:
  10.      print(day)
  11.  else:
  12.      print(sum(day_month[:month-1])+day)             #前面所有月的天数加上
  13.                                                      #本月第几天

例4-10 编写代码,输出由星号*组成的菱形图案,并且可以灵活控制图案的大小。

基本思路:首先使用一个for循环输出菱形的上半部分,然后再使用一个for循环输出菱形的下半部分。

    1.  n = int(input(’输入一个整数:'))
    2.  for i in range(n):
    3.      print(('* '*i).center(n*3))    #center()是字符串排版方法,居中对齐
    4.                                     #其中的参数n*3表示排版后字符串长度
    5.  for i in range(n, 0, -1):
    6.      print(('* '*i).center(n*3))

图4-3和图4-4分别为参数n等于6和9的运行效果。

图4-3 n=6的运行效果

图4-4 n=9的运行效果

例4-11 快速判断一个数是否为素数。

基本思路:除了2之外的所有偶数都不是素数;大于5的素数对6的余数必然是1或5,但对6的余数是1或5的不一定是素数;如果一个大于2的整数n不能被2或3到n的平方根之间的奇数整除,那么它是素数。

    1.  n = input("Input an integer:")
    2.  n = int(n)
    3.  #2是素数
    4.  if n == 2:
    5.      print('Yes')
    6.  #除了2之外的所有偶数必然不是素数
    7.  elif n%2 == 0:
    8.      print('No')
    9.  else:
   10.      #大于5的素数必然出现在6的倍数两侧
   11.      #因为6x+2、6x+3、6x+4肯定不是素数,假设x为大于1的自然数
   12.      m = n % 6
   13.      if m! =1 and m! =5:
   14.         print('No')
   15.      else:
   16.         #判断整数n是否能被3到n的平方根之间的奇数整除
   17.         for i in range(3, int(n**0.5)+1, 2):
   18.             if n%i == 0:
   19.                 print('No')
   20.                 break
   21.         else:
   22.             print('Yes')

例4-12 编写程序,计算组合数C(n,i),即从n个元素中任选i个,有多少种选法。

基本思路:以Cni(8,3)为例。

对于(5,8]区间的数,分子上出现一次而分母上没出现;(3,5]区间的数在分子、分母上各出现一次;[1,3]区间的数分子上出现一次而分母上出现两次。根据这一规律,可以编写如下非常高效的组合数计算程序。

    1.  def Cni(n, i):
    2.      if not (isinstance(n, int) and isinstance(i, int) and n >=i):
    3.         print('n and i must be integers and n must be  >=i.')
    4.         return
    5.      result = 1
    6.      #使用i和n-i把1到n之间的自然数分成3个区间
    7.      #使用Min表示i和n-i中较小的数,Max表示其中较大的数
    8.      Min, Max = sorted((i, n-i))
    9.      for i in range(n,0, -1):
   10.         if i >Max:
   11.             result *= i
   12.         elif i<=Min:
   13.             result /= i
   14.      return result
   15.
   16.  print(Cni(6,2))

例4-13编写程序,输入一个自然数n,然后计算并输出前n个自然数的阶乘之和1!+2!+3!+…+n!的值。

基本思路:在前一项(n-1)!的基础上再乘以n就可以得到下一项。

    1.  n = int(input(’请输入一个自然数:'))
    2.  #使用result保存最终结果,t表示每一项
    3.  result, t = 1, 1
    4.  for i in range(2, n+1):
    5.      #在前一项的基础上得到当前项
    6.      t *= i
    7.      #把当前项加到最终结果上
    8.      result += t
    9.  print(result)

例4-14 编写代码,模拟决赛现场最终成绩的计算过程。至少有3个评委,打分规则为删除最高分和最低分之后计算剩余分数的平均分。

基本思路:首先使用一个循环要求用户输入评委人数(应大于2,至少有3个评委),然后再使用一个循环输入每个评委的打分,在两个循环中都使用了异常处理结构来保证用户输入的是整数,最后删除最高分和最低分,并计算剩余分数的平均分。

   1.  while True:
   2.      try:
   3.         n = int(input(’请输入评委人数:'))
   4.         if n <= 2:
   5.             print(’评委人数太少,必须多于2个人。')
   6.         else:
   7.             break
   8.      except:
   9.         #pass是空语句,表示什么也不做
  10.         pass
  11.
  12.  scores = []
  13.
  14.  for i in range(n):
  15.      #这个while循环用来保证用户必须输入0到100之间的数字
  16.      while True:
  17.         try:
  18.             score = input(’请输入第{0}个评委的分数:'.format(i+1))
  19.             #把字符串转换为实数
  20.             score = float(score)
  21.             assert 0<=score<=100
  22.             scores.append(score)
  23.             #如果数据合法,跳出while循环,继续输入下一个评委的分数
  24.             break
  25.         except:
  26.             print(’分数错误’)
  27.
  28.  #计算并删除最高分与最低分
  29.  highest = max(scores)
  30.  lowest = min(scores)
  31.  scores.remove(highest)
  32.  scores.remove(lowest)
  33.  finalScore = round(sum(scores)/len(scores),2)
  34.
  35.  formatter = ’去掉一个最高分{0}\n去掉一个最低分{1}\n最后得分{2}'
  36.  print(formatter.format(highest, lowest, finalScore))

例4-15 编写程序,实现人机对战的尼姆游戏。

问题描述:尼姆游戏是这样一个游戏:假设有一堆物品,计算机和人类玩家轮流从其中拿走一部分。在每一步中,人或计算机可以自由选择拿走多少物品,但是必须至少拿走一个并且最多只能拿走一半物品,然后轮到下一个玩家。拿走最后一个物品的玩家输掉游戏。

基本思路:在每次循环中让人类玩家先拿走一定数量的物品,然后再让计算机取走一些物品,要求拿走的物品数量不超过剩余数量的一半。如果物品全部取完则结束游戏,并且判定拿走最后一个物品的玩家为输。

   1.  from random import randint
   2.
   3.  n = int(input(’请输入一个正整数:'))
   4.  while n  > 1:
   5.      #人类玩家先走
   6.      print("该你拿了,现在剩余物品数量为:{0}".format(n))
   7.      #确保人类玩家输入合法整数值
   8.      while True:
   9.         try:
  10.             num = int(input(’输入你要拿走的物品数量:'))
  11.             #确保拿走的物品数量不超过一半
  12.             assert 1 <= num <= n//2
  13.             break
  14.         except:
  15.             print(’最少必须拿走1个,最多可以拿走{0}个。'.format(n//2))
  16.      n -= num
  17.      if n == 1:
  18.         print(’恭喜,你赢了!')
  19.         break
  20.      #计算机玩家随机拿走一些,randint()用来生成指定范围内的一个随机数
  21.      n -= randint(1, n//2)
  22.  else:
  23.      print(’哈哈,你输了。')