机试基本算法笔记--动规

动规经典问题

1.递推求解

  • 斐波那契数列 F ( n ) = F ( n − 1 ) + F ( n − 2 ) ( n > 2 ) ; F ( 1 ) = F ( 2 ) = 1 F(n) = F(n-1)+F(n-2)(n>2) ;F(1)=F(2)=1 F(n)=F(n1)+F(n2)(n>2);F(1)=F(2)=1
  • 台阶公式 F ( n ) = F ( n + 1 ) + F ( n + 2 ) ( n > 2 ) ; F ( 1 ) = 1 ; F ( 2 ) = 2 F(n)=F(n+1)+F(n+2)(n>2) ;F(1)=1;F(2)=2 F(n)=F(n+1)+F(n+2)(n>2);F(1)=1;F(2)=2
  • 排错公式 F ( n ) = ( n − 1 ) F ( n − 1 ) + ( n − 2 ) F ( n − 2 ) ( n > 2 ) ; F ( 1 ) = 0 ; F ( 1 ) = 1 F(n)=(n-1)F(n-1)+(n-2)F(n-2)(n>2);F(1)=0;F(1)=1 F(n)=(n1)F(n1)+(n2)F(n2)(n>2);F(1)=0;F(1)=1

补充:

N N N阶楼梯上楼问题:每次上楼可以上一阶楼梯或两阶楼梯, N N N阶楼梯可以有多少种方式?
首先 F ( 1 ) = 1 F(1)=1 F(1)=1 F ( 2 ) = 2 F(2)=2 F(2)=2是可以直接得到的,那么当 n n n大于 2 2 2时,我考虑每种上台阶方式的最后一步,由于只有两种行走方法,因此它只可能是从 n − 1 n-1 n1阶经过一步走到 n n n阶,或者从 n − 2 n-2 n2阶经过两步走到 n n n阶。因此 F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2)

排错问题 n n n个信封,问如果所有的信都装错信封,一共有多少种装错方式?
假设有 n n n封信,第一封信可放在( 2 2 2~ n n n)的任一个信封里,共 n − 1 n-1 n1种放法,设第一封信放在了第 k k k个信封里,若此时第 k k k封信放在了第 1 1 1个信封里,则只要将剩下的 n − 2 n-2 n2错排,即 F ( n − 2 ) F(n-2) F(n2),若第 k k k封信没有放在了第 1 1 1个信封里,可将第 1 1 1封信的位置看成是“第 k k k个位置”,即将 n − 1 n-1 n1封信错排,即为 F ( n − 1 ) F(n-1) F(n1),因此 F ( n ) = ( n − 1 ) F ( n − 1 ) + ( n − 2 ) F ( n − 2 ) ( n > 2 ) ; F ( 1 ) = 0 ; F ( 1 ) = 1 F(n)=(n-1)F(n-1)+(n-2)F(n-2)(n>2);F(1)=0;F(1)=1 F(n)=(n1)F(n1)+(n2)F(n2)(n>2);F(1)=0;F(1)=1

2.最长递增子序列

已知序列 { a 1 , a 2 , . . . , a n } \{a_{1},a_{2},...,a_{n}\} {a1,a2,...,an}中,取出若干数组成新的序列 { a i 1 , a i 2 , . . . , a i m } \{a_{i1},a_{i2},...,a_{im}\} {ai1,ai2,...,aim},其中下标 i 1 i1 i1, i 2 i2 i2,…, i m im im保持递增,即新数列中各个数之间依旧保持原数列中的先后顺序,那么称 { a i 1 , a i 2 , . . . , a i m } \{a_{i1},a_{i2},...,a_{im}\} {ai1,ai2,...,aim}为原序列的一个子序列,如果在子序列中,当下标 i x > i y ix>iy ix>iy a i x > a i y a_{ix}>a_{iy} aix>aiy,那么称这个子序列为原序列的一个递增子序列。

F ( i ) F(i) F(i)表示序列中以 a i a_{i} ai为末元素的最长递增子序列的长度。则有如下的递推方程:

这个递推方程的意思是,在求以 a i a_{i} ai为末元素的最长递增子序列时,找 a j a_{j} aj j &lt; i j&lt;i j<i a j &lt; a i a_{j}&lt;a_{i} aj<ai。如果这样的元素存在,那么对所有 a j a_{j} aj,都有一个以 a j a_{j} aj为末元素的最长递增子序列的长度 F ( j ) F(j) F(j),把其中最大的 F ( j ) F(j) F(j)选出来,那么 F ( i ) F(i) F(i)就等于最大的 F ( j ) F(j) F(j)加上 1 1 1,即以 a i a_{i} ai为末元素的最长递增子序列,等于以使 F ( j ) F(j) F(j)最大的那个 a j a_{j} aj为末元素的递增子序列最末再加上 a i a_{i} ai;如果这样的元素不存在,那么 a i a_{i} ai自身构成一个长度为 1 1 1的以 a i a_{i} ai为末元素的递增子序列。

for(int i=0;i<n;i++)
{
	int imax=1;
	for(int j=0;j<i;j++)
	{
		if(a[j]<a[i])
			imax = max(imax,f(j)+1)
	}
	f[i]=imax;
}

3.最长公共子序列(LCS)

有两个字符串 S 1 S 2 S_{1}S_{2} S1S2,求第三个字符串 S 3 S_{3} S3,它同时为 S 1 S 2 S_{1}S_{2} S1S2的子串,且要求它的长度最长。我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示 S 1 S_{1} S1中前 i i i个字符与 S 2 S_{2} S2中前 j j j个字符的最长公共子串的长度。

S 1 [ i ] = S 2 [ j ] S_{1}[i]=S_{2}[j] S1[i]=S2[j] d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j]=dp[i-1][j-1]+1 dp[i][j]=dp[i1][j1]+1
S 1 [ i ] ! = S 2 [ j ] S_{1}[i]!=S_{2}[j] S1[i]!=S2[j] d p [ i ] [ j ] dp[i][j] dp[i][j] S 1 S_{1} S1中前 i − 1 i-1 i1个字符与 S 2 S_{2} S2中前 j j j个字符的最长公共子串 S 1 S_{1} S1中前 i i i个字符与 S 2 S_{2} S2中前 j − 1 j-1 j1个字符的最长公共子串 的较大值
显然,当 i = 0 i=0 i=0 j = 0 j=0 j=0时,即 d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0 d p [ i ] [ 0 ] = 0 dp[i][0]=0 dp[i][0]=0

那么 d p [ i ] [ j ] dp[i][j] dp[i][j]的地推公式:

d p [ i ] [ j ] { d p [ i − 1 ] [ j − 1 ] + 1 S 1 [ i ] = S 2 [ j ] m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) S 1 [ i ] ! = S 2 [ j ] d p [ 0 ] [ j ] = d p [ i ] [ 0 ] = 0 0 ≤ i ≤ n , 0 ≤ j ≤ m dp[i][j]\left\{\begin{matrix} dp[i-1][j-1]+1 &amp; S_{1}[i]=S_{2}[j]\\ max(dp[i-1][j],dp[i][j-1]) &amp;S_{1}[i]!=S_{2}[j] \\ dp[0][j]=dp[i][0]=0 &amp;0\leq i\leq n,0\leq j\leq m \end{matrix}\right. dp[i][j]dp[i1][j1]+1max(dp[i1][j],dp[i][j1])dp[0][j]=dp[i][0]=0S1[i]=S2[j]S1[i]!=S2[j]0in,0jm

4.0-1背包问题

0 − 1 0-1 01背包:有一个容量为 V V V的背包和一些物品,这些物品分别有两个属性,体积 v v v和价值 w w w,每个物品只有两个状态,取或不取。要求用这个背包装下价值尽可能多的物品,求该最大价值,背包可以不被装满。

我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示背包总体积不超过j的情况下,前i个物品所能达到的最大价值。
初始时, d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0。若物品 i i i放入背包,设其体积为 w w w,价值为 v v v,则 d p [ i ] [ j ] dp[i][j] dp[i][j]= d p [ i − 1 ] [ j − w ] + v dp[i-1][j-w]+v dp[i1][jw]+v,即在总体积不超过 j − w j-w jw时前 i − 1 i-1 i1件物品可组成的最大价值的基础上再加上 i i i物品的价值 v v v;若物品不加入背包,则 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j],即此时与总体积不超过 j j j的前 i − 1 i-1 i1件物品组成的价值最大值等价。选择他们之中较大值成为状态 d p [ i ] [ j ] dp[i][j] dp[i][j]的值。综上, 0 − 1 0-1 01背包的状态转移方程为:
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j − w ] + v , d p [ i − 1 ] [ j ] ) dp[i][j]=max(dp[i-1][j-w]+v,dp[i-1][j]) dp[i][j]=max(dp[i1][jw]+v,dp[i1][j])

更通俗点讲就是:
(1)当w[i] > j的时候,说明放不下去,所以肯定不能放i号物品,所以:
m[i][j] = m[i-1][j]
(2)当w[i] <= j的时候,说明放的下去,那么问题就是放不放,如果放的话价值是m[i-1][j-w[i]] + v[i];如果不放下去,就是m[i][j] = m[i-1][j]。所以放不放显然取决于两个值的大小。

if(j>=w[i])
    dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);  
else  
    dp[i][j]=dp[i-1][j];  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值