Udacity Lesson:Designs of Computer Program_Zebra Puzzle solution

一、问题描述

  1. 一条街上有五座不同颜色的房子,每座房子住着不同国籍的人,每个人抽不同的烟,喝不同的饮料,养不同的宠物。
  2. 英国人住在红房子里。
  3. 西班牙人养狗。
  4. 住在绿房子里的人喝咖啡。
  5. 乌克兰人喝茶。
  6. 绿房子就在乳白色房子的右边。
  7. 抽流金岁月(烟名)的人养蜗牛。
  8. 抽薄荷烟的住在黄房子里。
  9. 住在中间的房子里的人喝牛奶。
  10. 挪威人住在第一座房子里。
  11. 抽契斯特菲尔德(烟名)的人住在养狐狸的人旁边。
  12. 抽薄荷烟的人住在养马的人旁边。
  13. 抽好彩(烟名)的人喝橙汁。
  14. 日本人抽百乐门(烟名)。
  15. 挪威人住在蓝房子隔壁。
    那么,谁喝水(water)?谁养斑马(zebra)?

二、解决问题思路

首先把问题所涉及到的概念列举出来:house和properties。那么properties包含五个属性分别是:房子的颜色,人的国籍,烟,饮料和宠物

1.如果仅仅为house分配一个properties属性,例如颜色,那么共有**5!**种可能性;若是把这五个属性排列组合分配到五个房子中,那么共有5!5(约等于20billion)种可能性。我们都知道,计算机每秒钟可以处理1billion条指令
2.houses = [1,2,3,4,5] 这是其中一种可能
orderings= F(houses)
for (red,green,ivory,yellow,blue) in orderings:
这里的F应该是排列函数,在itertools模块里面有permutations函数,那么len(orderings)=120

import itertools

def imright(h1, h2):
    # "House h1 is immediately right of h2 if h1-h2 == 1."
    return h1-h2 == 1

def nextto(h1, h2):
    #    "Two houses are next to each other if they differ by 1."
    return abs(h1-h2) == 1

def zebra_pazzle():
    houses = first, _, middle, _, _ = [1, 2, 3, 4, 5]
    orderings = list(itertools.permutations(houses))    # 1 constrains
    return next((WATER, ZEBRA)
            for (red, green, ivory, yellow, blue) in orderings
            if imright(green, ivory)  #6
            for (Englishman, Spaniard, UKranian, Japanese, Norwegian) in orderings
            if Englishman is red   # 2
            if Norwegian is first  # 10
            if nextto(Norwegian, blue)  #15
            for (coffee, tea, milk, oj, WATER) in orderings
            if coffee is green  # 4
            if UKranian is tea  # 5
            if milk is middle  # 9
            for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments) in orderings
            if Kools is yellow  # 8
            if LuckyStrike is oj  # 13
            if Japanese is Parliaments  # 14
            for (dog, snails, fox, horse, ZEBRA) in orderings 
            if Spaniard is dog   # 3
            if OldGold is snails  # 7
            if nextto(Chesterfields, fox)  # 11 
            if nextto(Kools, horse)  # 12
   )
   print(zebra_pazzle())
>>>(1, 5)

#1-15分别是问题中的15个限制条件。调整顺序可以消除冗余,可以在一秒钟之内得到答案。所以最终结果是:第一个房子喝水,第五个房子拥有zebra

关于生成器(generator)

  1. 最直观的:generator 用小括号表示( ),而[ ]则表示list
  2. 一个例子:
def sq(x): 
    print('sq called', x)
    return x*x
g = (sq(x) for x in range(10) if x%2 == 0)

g是一个generator expression,调用next(),那么将会依次输出g里面的东西,直到g为空。所以每取出一个,g里面就会少一个元素,当g为空时在调用next(),将会报错

print(g) 
>>><generator object <genexpr> at 0x000001561771DCA8>
next(g)
>>>sq called 0
next(g)
>>>sq called 2
next(g)
>>>sq called 4
next(g)
>>>sq called 6
next(g)
>>>sq called 8
next(g)
>>>Traceback (most recent call last):
  File "E:/untitled1/prac.py", line 50, in <module>
    next(g)
StopIteration

故为了避免编译器报错,我们可以这样做

for x2 in (sq(x) for x in range(10) if x%2 == 0): pass
>>>sq called 0
>>>sq called 2
>>>sq called 4
>>>sq called 6
>>>sq called 8

为什么选用生成器来解决问题

  1. less indentation
    因为有太多的for和if语句,那么将会造成许多缩进,可能页面的空间会不够用
  2. stop early
  3. easier to edit

听这一节课自己不熟悉的小概念

  1. *arg----*arg出现在两个地方:
    一个是定义函数的形参;这意味着该函数可以带任何数量的参数,他们应该在一个名叫arg的tuple中;
    一个是函数调用的时候的参数 :调用的时候unpack该tuple;
    下面是一个小例子:
第一个地方:def something(fn,*arg):
第二个地方:fn(*arg)
若something(fn,(1,2,3))
那么调用的时候就是fn(1,2,3)

其实这仅仅是pack和unpack参数(argument)的一种方式

  1. 对于列表里面嵌套for语句,始终有些迷糊。下面是我的另外一篇介绍该内容的博客,请参考:
    https://blog.csdn.net/weixin_43294226/article/details/88902779
  2. 求函数的运行时间的函数,这里面应用到了*arg和list嵌套for语句:
import time

def timedcall(fn, *args):
    "Call function with args; return the time in seconds and result."
    t0 = time.clock()      # clock()求当时的时间
    result = fn(*args)
    t1 = time.clock()
    return t1-t0, result

def average(numbers):
    "Return the average (arithmetic mean) of a sequence of numbers."
    return sum(numbers) / float(len(numbers)) 

def timedcalls(n, fn, *args):
    """Call fn(*args) repeatedly: n times if n is an int, or up to
    n seconds if n is a float; return the min, avg, and max time"""
    # Your code here.
 
    if isintance(n,int):
        times = [timedcall(fn, *args)[0] for _ in range(n)]
    else:
        times = []
        while sum(times) < n:
            times.append(timedcall(fn,*args)[0])
    return min(times), average(times), max(times)     

generator function

这里接着讲到了generator function,如何应用在上面的问题中我就不介绍了,因为他比起上面给出的问题解决方法稍微差了那么一点,但是generator function是什么我们还是要介绍一下。

def ints(start, end = None):   # end本可以不等于None,是一个正常的数字就可以,但是它一旦等于None了,就表明这个函数要无休止的进行下去了                          
    i = start
    while i <= end or end is None:
        yield i
        i = i + 1
    
def all_ints():
    "Generate integers in the order 0, +1, -1, +2, -2, +3, -3, ..."
    # Your code here.
    yield 0
    for i in ints(1):
        yield +i
        yield -i

这两个函数都含有yield,所以他们都是generator function,这是使函数区别于普通函数的根本。

aspect-oriented program

aspect-oriented program 遵循以下三个aspect:
correct
efficient
debug

结语

zebra_puzzle 问题就告一段落,如有不好的地方,还请朋友们指正,感谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值