动态编程,重叠子问题,优化子结构
一般来说,递归型问题都具有重叠子问题(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)。
用户自制一个字典,记录下第一次执行某值得到的结果,再次执行该值时,先在字典中查找(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)
首先,明确一个概念——“最优子结构”,英文解释如下
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 ,这是一个指数型的问题。
我们用决策树来分析该问题
代码如下
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)
背包问题的分析,面向对象编程介绍
其实接下来这段对于背包问题的分析我并不十分理解
首先,是对于 Memorization 化的决策树解法的复杂度进行分析。分析指出,这个解法的时间复杂度是 O(ns) ,空间复杂度也为 O(ns) ,其中 n 指物品的数量, s 指的是背包的容积
接下来都是没弄懂的东西
一个小变体,如果将约束条件改为总重量+总容积限制呢?
那么,数学表述应该为?
接下来介绍一些面向对象的知识
首先,模块( Module/Modularity )
例如:
math.sqrt(n)
核心思想是:生成用户定义的类型
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没有这样的绝对的机制。
封装,继承,映射
代码例子
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循环