标题 | 教材(版本) | 试题 |
---|---|---|
钢条切割 | 算法导论(3) | 18-1 |
矩阵链乘法 | 算法导论(3) | 16-2-64,19-1-62 |
最长公共子序列 | 算法导论(3) | 17-2-62,15-2 |
最优二叉查找树 | 算法导论(3) | |
0-1背包 | 软件设计师教程(5) | 16-1-62,19-2 |
装配线调度 | 算法导论(2) | 17-1-62 |
适用于动态规划的问题:
- 最优子结构.
- 重叠子问题.
备忘法:
记录子问题结果.
回溯法:
由结果重建过程.
“大多数人都是这样:如果你告诉他们事情的经过,他们就会告诉你接下来的结果。他们默默地对事情的经过进行综合分析,通过取舍,就能得出结论。只有少数人,如果你把结果告诉了他们,他们就能通过他们内在的意识,推断出造成这种结果的每个步骤是什么。这就是在我说到’回溯推理’或者’分析的方法’时,所指的那种能力。”——《血字的研究》
钢条切割
递推式(双侧切割):
递推式(单侧切割):
带备忘的自顶向下法:
var r=[],s=[]
function topDownCutRod(p,n){
if(!r[n]){
r[n]=p[n]
s[n]=0
for(var i=1;i<=n/2;i++){
var tmp=topDownCutRod(p,i)+topDownCutRod(p,n-i)
if(tmp>r[n]){
r[n]=tmp
s[n]=i
}
}
}
return r[n]
}
var p=[0,1,5,8,9,10,17,17,20,24,30]
topDownCutRod(p,8)
console.log(r,s)
自底向上法:
var r=[],s=[]
function bottomUpCutRod(p,n){
for(var i=1;i<=n;i++){
r[i]=p[i]
s[i]=0
for(var j=1;j<=i/2;j++){
var tmp=r[j]+r[i-j]
if(tmp>r[i]){
r[i]=tmp
s[i]=j
}
}
}
return r[n]
}
var p=[0,1,5,8,9,10,17,17,20,24,30]
bottomUpCutRod(p,8)
console.log(r,s)
回溯法重建切割过程:
function traceBackwardsCutRod(n){
var t=[]
while(s[n]){
t.push(s[n])
n-=s[n]
}
t.push(n-s[n])
console.log(t)
}
traceBackwardsCutRod(8)
最长公共子序列
递推式:
自底向上法:
var c=[]
function bottomUpLCS(x,y,m,n){
for(var i=0;i<=m;i++){
c[i]=[0]
}
for(var i=1;i<=n;i++){
c[0][i]=0
}
for(var i=1;i<=m;i++){
for(var j=1;j<=n;j++){
if(x[i-1]==y[j-1]){
c[i][j]=c[i-1][j-1]+1
}else{
c[i][j]=Math.max(c[i][j-1],c[i-1][j])
}
}
}
}
var x='ABCADAB',y='BDCABA'
var m=x.length,n=y.length
bottomUpLCS(x,y,m,n)
console.log(c)
回溯法重建LCS:
var z=[]
function traceBackwardsLCS(m,n){
for(var i=m,j=n;i>0&&j>0;){
if(c[i][j]==c[i][j-1]){
j--
}else if(c[i][j]==c[i-1][j]){
i--
}else{
z.unshift(x[i-1])
i--
j--
}
}
}
traceBackwardsLCS(m,n)
console.log(z)
0-1背包
递推式:
带备忘的自顶向下法:
var c=[]
function topDownKnapsack(v,w,i,j){
if(!c[i]){
c[i]=[]
}
if(!c[i][j]){
if(i==0||j==0){
c[i][j]=0
}else{
c[i][j]=topDownKnapsack(v,w,i-1,j)
if(j-w[i-1]>=0){
var temp=topDownKnapsack(v,w,i-1,j-w[i-1])+v[i-1]
if(c[i][j]<temp){
c[i][j]=temp
}
}
}
}
return c[i][j]
}
var v=[4,5,10,11,13]
var w=[3,4,7,8,9]
var t=17
topDownKnapsack(v,w,v.length,t)
console.log(c)
回溯法重建装包过程:
var s=[]
function traceBackwardsKnapsack(v,w,i,j){
if(i>0){
if(c[i][j]!=c[i-1][j]&&c[i][j]>0){
s[i-1]=1
traceBackwardsKnapsack(v,w,i-1,j-w[i-1])
}else{
s[i-1]=0
traceBackwardsKnapsack(v,w,i-1,j)
}
}
}
traceBackwardsKnapsack(v,w,v.length,t)
console.log(s)