Partition Problem 分块问题
这里想解决的问题是,比如我们有一串数字:{1,2,4,2,5,2,1,1},咱们能不能把这串数字,分成两串,并且这两个串的和相等。
比如说分割成{1,2,4,2}和{5,2,1,1},这两串的和相等都是9.
或者分割成{4,5}和{1,2,2,2,1,1},这两串的和都是9.
那么改用什么方法找到分割方法呢?
如果把一串数字,分割成等和的两个子串,那么每个子串的和应该是总和的一半对吧!
那就相当于找几个数字,满足他们相加起来等于这个sum/2
这是不是就相当于是一个背包容量为sum/2的 0/1背包问题!
咱们只需要找出一串满足,数字和为sum/2,另外一串肯定和也为sum/2。就相当于已经完成了平分问题了!
但是咱们在这里再考虑一下:如果sum是一个奇数,那肯定不能平分!
但是sum是偶数的话,就存在平分的可能了!
a=[1,2,4,2,5,2,1,1]
def get_partition(a):
sum=0
for i in range(len(a)):
sum+=a[i]
if sum%2!=0: #判断是否是奇数
return 0
else:
half=sum/2
1.创建dp数组
参照0/1背包问题创建一下dp数组,创建出一个二维数组。dp[ i ][ j ]意味着当前情况下,你的背包能容纳的最大价值。同时对数组的第一行进行一个初始化!
a=[1,2,4,2,5,2,1,1]
def get_partition(a):
sum=0
for i in range(len(a)):
sum+=a[i]
if sum%2!=0: #判断是否是奇数
return =0
else:
half=sum/2
dp=[[0 for i in range(half+1)] for j in range(len(a))]
for i in range(a[0],half+1):
dp[0][i]=a[0]
2.确定递推公式
递推公式完全参考0/1背包问题
if j>=a[ i ] dp[ i ][ j ]=max(dp[ i-1 ][ j ], dp[ i-1 ][ j-a[ i ] ]+a[ i ])
if j
分别代表着能否放得下a[ i ]这个物体
随后就一步步递推,直到找到目标的half吧!
用代码实现一下吧!
a=[1,2,4,2,5,2,1,1]
def get_partition(a):
sum=0
for i in range(len(a)):
sum+=a[i]
if sum%2!=0: #判断是否是奇数
return 0
else:
half=sum/2
dp=[[0 for i in range(half+1)] for j in range(len(a))]
for i in range(a[0],half+1):
dp[0][i]=a[0]
for i in range(1,len(a)):
for j in range(0,half+1):
if j<a[i]:
dp[i][j]=dp[i-1][j]
else:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i])
return dp[len(a)-1][half]==half
在本节pdf最后,介绍了另外一种通过布尔(bool)数组,True False值来表示的矩阵,来表示dp数组,其实这两个东西确实没差别,我们掌握一个就够了!
两个问题,第一个是深度优先搜索,第二个是斐波那契数列问题的重述。
写这个的时候深度优先搜索我还没太搞懂,先开斐波那契数列问题的重述吧。
回忆一下,什么是斐波那契问题?我们之前是怎么处理这个问题的呢?
递归得到结果,或者是建立dp数组递归得到结果,希望你有印象哦!
那么,通过矩阵的方式我们是不是可以对Fn进行表示呢?
你看一下这个表达式,我们是不是把An求出来,Fn+1就求出来了!
但是具体应该怎么求呢,这个就要求助于我们线性代数的知识了,其实最开始我也不怎么会,看了看别人怎么做的,也算是哼哼哧哧写下来了。
得到这个表达式的好处是什么呢?其实就是我们可以直接通过公式求得斐波那契数列的值了!这样做,时间复杂度和空间复杂度很低!!
def get_fib(n):
return pow((1+5**0.5)/2,n)/(5**0.5)-pow((1-5**0.5)/2,n)/(5**0.5)
print(int(get_fib(10)))
Depth-First Search 深度优先搜索
在曾经所学的图论那里,我们想解决怎么从’Me’到‘Ed’的最短距离。想一下我们之前是怎么解决这个问题的?
我们之前所使用的方法是:借助队列问题实现广度搜索!一层一层实现遍历寻找目标点。
在这里我们想通过深度搜索去搜索目标点。
深度搜索的实现是:针对每个点走到最深处,如果没有寻找到目标点,那就从下一个点走到最深处。
广度搜索能够寻找到最短路径。深度搜索能够实现快速搜素。
深度搜索可以通过递归方式,回溯实现。
同样是利用了 S:已经考虑过的结点的集合 T:N叉树
如果cur节点没有在S中出现过,才对其考虑,如果出现过,就不用考虑了。
cur节点添加在树中,再对cur的子节点进行深度搜索。
G = { 'A' : [ 'B', 'J', 'Me' ],
'B' : [ 'A' ],
'C' : [ 'D', 'P' ],
'D' : [ 'C', 'O' ],
'E' : [ 'F', 'J', 'K' ],
'F' : [ 'E', 'M' ],
'G' : [ 'K', 'S', 'Ed' ],
'H' : [ 'O', 'U' ],
'Me': [ 'A', 'I', 'N', 'V' ],
'I' : [ 'Me', 'Q' ],
'J' : [ 'A', 'E', 'L', 'Q', 'W' ],
'K' : [ 'E', 'G' ],
'L' : [ 'J', 'W' ],
'M' : [ 'E', 'S', 'T' ],
'N' : [ 'Me', 'V' ],
'O' : [ 'H', 'D' ],
'P' : [ 'C', 'U' ],
'Q' : [ 'I', 'J', 'X', 'Y' ],
'R' : [ 'Ed' ],
'S' : [ 'G', 'M', 'Y', 'Z' ],
'T' : [ 'M' ],
'U' : [ 'H', 'P' ],
'V' : [ 'Me', 'N' ],
'W' : [ 'J', 'L' ],
'X' : [ 'Q', 'Y' ],
'Y' : [ 'Q', 'S', 'X', 'Z' ],
'Ed': [ 'G', 'R', 'Z' ],
'Z' : [ 'S', 'Y', 'Ed' ] }
class tree:
class treenode:
def __init__(self,val,child=[]):
self.val=val
self.children=[]
def __init__(self):
self.root=None
def add(self,cur,parent):
if parent==None:
self.root=cur
else:
parent.children.append(cur)
s=[]
T=tree()
def DFS(G,cur,parent):
if cur not in s:
s.append(cur)
node=tree.treenode(val=cur)
T.add(node,parent)
for v in G[cur]:
DFS(G,v,node)
DFS(G,'Me',T.root)
为什么要这么写呢
首先需要对N叉树进行创建,他的树节点应该包括value和children两个部分。并且对add方法进行创建!
最后对伪代码形成Python代码就好啦。
第五天也就是第二周的内容学完了!我的渊宝是最棒的!
希望你这周作业一点问题都没有,写的嘎嘎好嘎嘎快!