MIT 6.00 导论课程笔记(四)

Lecture 13

动态编程,重叠子问题,优化子结构
一般来说,递归型问题都具有重叠子问题(overlapping sub-problem),例如以前讲过的裴波那契数列。

def fib2(x):
    global numCalls
    numCalls += 1
    print 'fib called with: ',n,' numCalls: ',numCalls
    if x == 0 or x == 1:
        return 1
    else:
        return fib(x-1)+fib(x-2)

这个函数有一个执行时间上的问题,在执行时,他还会重复执行一些以前执行过的内容,随着问题规模的增大,这个劣势越发的明显。
为此,John提出了一种记忆化的方法(Memorization)。

Memorization

用户自制一个字典,记录下第一次执行某值得到的结果,再次执行该值时,先在字典中查找(hash算法),没有再执行。
这种方法有一个统一的名字叫 Table-lookup ,它的特例是 Memorization
Memorization化的裴波那契代码如下:

def FastFib(n, memo):
    global numCalls 
    numCalls += 1
    print 'fib called with ',n
    if not n in memo:
        memo[n] = FastFib(n-1,memo) + FastFib(n-2, memo)
    return memo[n]

def fib(n):
    memo = {0:1,1:1}
    return FastFib(n,memo)

0/1 背包问题

首先,明确一个概念——“最优子结构”,英文解释如下

Global optimal solution can be constructed from optimal solution to sub-problems.

意为,一个问题的最优解可以由子问题的优解构成。
重新描述不连续背包问题:

We have a collection of objects called ‘A’, for each object in A we have found the subject of A that has the maximum value subject to the weight constraint.

,寻找在约束条件下取得最大值的A的子集。
假设A中有 n 个对象, |A|=n ,那么可能的子集数量为 2n ,这是一个指数型的问题。
我们用决策树来分析该问题

n=3,maxWeight=5

w=[5,3,2]

v=[9,7,8]

我们使用 depth first/left first 的方法进行分析

决策树如图
代码如下

def maxValue(w,v,i,aW):
    '''w:=weight
    v:=value,i:=index,aW:=available weight
    return:=total value'''
    print 'call ',i,' ',aW
    global numCalls
    numCalls += 1
    if i == 0:
        if w[i] <= aW:
            return v[i]
        else:
            return 0
    #dont't take branch
    without_i = maxValue(w,v,i-1,aW)
    if w[i] > aW:
        return without_i
    else:
        with_i = v[i] + maxValue(w,v,i-1,aW-w[i])
    return max(with_i,without_i)

这里依旧使用Memorization方法

def fastMaxVal(w,v,i,aW,m):
    global numCalls
    numCalls += 1
    try:
        return m[(i,aW)]
    except KeyError:
        if i == 0:
            if w[i] <= aW:
                m[(i,aW)] = v[i]
                return v[i]
            else:
                m[(i,aW)] = 0
                return 0
        without_i =fastMaxVal(w,v,i-1,aW,m)
        if w[i] > aW:
            m[(i,aW)] = without_i
            return without_i
        else:
            with_i = v[i] + fastMaxVal(w,v,i-1,aW-w[i],m)
        m[(i,aW)] = max(with_i,without_i)
        return m[(i,aW)]


def maxVal0(w,v,i,aW):
    m = {}
    return fastMaxVal(w,v,i,aW,m)

Lecture 14

背包问题的分析,面向对象编程介绍
其实接下来这段对于背包问题的分析我并不十分理解
首先,是对于 Memorization 化的决策树解法的复杂度进行分析。分析指出,这个解法的时间复杂度是 O(ns) ,空间复杂度也为 O(ns) ,其中 n 指物品的数量, s 指的是背包的容积
接下来都是没弄懂的东西

  • 这个问题的复杂度取决于问题的规模+解法的规模(size of problem + size of solution)
  • 伪多项式算法( Pseudo-polynomial algorithm )
  • 输入数值的多项式(polynomial in numeric value of input)

一个小变体,如果将约束条件改为总重量+总容积限制呢?
那么,数学表述应该为?

func=inPiXi

Cons:=i=1nWiXiC,i=1nViXiK

C 为背包的总重量, K 为背包的总容量
总结:

  1. 时空权衡
  2. 不要惧怕指数型问题
  3. 动态编程是有用的
  4. 问题降级

模块化

接下来介绍一些面向对象的知识
首先,模块( Module/Modularity )

  • 是相关函数的一个集合(collection of related functions)
  • 使用 号来调用函数(refer to functions using notation)

例如:

math.sqrt(n)

Classes

  • 对象( object ):数据和函数的集合( a collectio of data and functions )
  • 类(classes):有共同特征的对象的集合(a collectio of objects with characteristics in common)

核心思想是:生成用户定义的类型

Lecture 15

abstract data type , classes and methods
举个类的例子:

#二维平面上的点如何表示?
#第一种方法:使用函数
def addPoint(p1,p2):
    r = []
    r.append(p1[0]+p2[0])
    r.append(p1[1]+p2[1])
    return r

#p = [1,2]
#q = [3,1]
#r = addPoint(p,q)
#print r

'''point as classes'''
class cartesianPoint():
    pass
cp1 = cartesianPoint()
cp2 = cartesianPoint()
cp1.x = 1.0
cp1.y = 2.0
cp2.x = 3.0
cp2.y = 1.0

def samePoint(p1,p2):
    return (p1.x == p2.x) and (p1.y == p2.y)
def printPoint(p):
    print '['+str(p.x)+', '+str(p.y)+']'

class polarPoint():
    pass
pp1 = polarPoint()
pp2 = polarPoint()
pp1.radius = 1.0
pp1.angle = 0
pp2.radius = 2.0
pp2.angle = math.pi/4.0
#我们希望同一个点既可以用笛卡尔坐标又可以用极坐标表示
class cPoint:
    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.radius = math.sqrt(self.x*self.x+self.y*self.y)
        self.angle = math.atan2(self.y,self.x)
    def cartesian(self):
        return (self.x,self.y)
    def polar(self):
        return (self.radius,self.angle)
    def __str__(self):
        return '('+str(self.x)+','+str(self.y)+')'
    def __cmp__(self,other):
        return (self.x > other.x) and (self.y > other.y)
#线段的类
class Segment:
    def __init__(self,start,end):
        self.start = start
        self.end = end
    def length(self):
        #注意不要对负数开平方
        return math.sqrt((self.start.x-self.end.x)*(self.start.x-self.end.x)+(self.start.y-self.end.y)*(self.start.y-self.end.y))

类(Class):为对象创建实例的模板
浅相等:指向同一块内存区域
深相等:可以用户定义如何相等
self:
使用self指向特定的实例
数据隐藏(Data hiding):只能从定义的方法中获取实例中的值。

但是python没有这样的绝对的机制。

Lecture 16

封装,继承,映射
代码例子

class Person(object):
    def __init__(self,family_name,first_name):
        self.family_name = family_name
        self.first_name = first_name
    def familyName(self):
        return self.family_name
    def firstName(self):
        return self.first_name
    def __cmp__(self,other):
        return cmp((self.family_name,self.first_name),(other.family_name,other.first_name))
    def __str__(self):
        return '<Person: %s %s>'%(self.first_name,self.family_name)
    def say(self,toWhom,something):
        return self.first_name+' '+self.family_name+' says to '+toWhom.firstName()+' '+toWhom.familyName()+': '+something
    def sing(self,toWhom,something):
        return self.say(toWhom,something+' tra la la')


class MITPerson(Person):
    '''subclass can inherit Person's attribute'''
    nextIDNum = 0
    def __init__(self,family_name,first_name):
        Person.__init__(self,family_name,first_name)
        self.idNum = MITPerson.nextIDNum
        MITPerson.nextIDNum += 1
    def getIdNum(self):
        return self.idNum
    def __str__(self):
        return '<MIT Person: %s %s>'%(self.first_name, self.family_name)
    def __cmp__(self,other):
        return cmp(self.idNum, other.idNum)

#p1 = MITPerson('Smith','Fred') 
#p2 = MITPerson('Foobar','Jane') 
#print p1.getIdNum() 
#print p2.getIdNum()

class UG(MITPerson):
    def __init__(self,family_name,first_name):
        MITPerson.__init__(self,family_name,first_name)
        self.year = None
    def setYear(self,year):
        if year > 5:
            raise OverflowError('Too many')
        self.year = year
    def getYear(self):
        return self.year
    def say(self,toWhom,something):
        return MITPerson.say(self,toWhom,'Excuse me, but '+something)

class Prof(MITPerson):
    def __init__(self,family_name,first_name,rank):
        MITPerson.__init__(self,family_name,first_name)
        self.rank = rank
        self.teaching = {}
    def addTeaching(self,term,subj):
        try:
            self.teaching[term].append(subj)
        except KeyError:
            self.teaching[term] = [subj]
    def getTeaching(self,term):
        try:
            return self.teaching[term]
        except KeyError:
            return None
    def lecture(self,toWhom,something):
        return self.say(toWhom,something+' as it is obvious')
    def say(self,toWhom,something):
        if type(toWhom) == UG:
            return MITPerson.say(self,toWhom,'i do not understand why you say '+something)
        elif type(toWhom) == Prof:
            return MITPerson.say(self,toWhom,'i really liked your paper on '+something)
        else:
            return self.lecture(toWhom,something)

class Faculty(object):
    def __init__(self):
        self.names = []
        self.IDs = []
        self.members = []
        self.place = None
    def add(self,who):
        if type(who) != Prof:
            raise TypeError('not a professor!')
        if who.getIdNum() in self.IDs:
            raise ValueError('duplicate ID')
        self.names.append(who.familyName())
        self.IDs.append(who.getIdNum())
        self.members.append(who)
    def __iter__(self):
        self.place = 0
        return self
    def next(self):
        if self.place >= len(self.names):
            raise StopIteration
        self.place += 1
        return self.members[self.place-1]

唯一又要说的是一个迭代器:
iter和next方法共同创造了for循环

猜你喜欢

转载自blog.csdn.net/sjz_hahalala479/article/details/55803217