zoukankan      html  css  js  c++  java
  • 算法54---动态规划

    一、啥问题可以用动态规划来解决【采用空间来存储重复计算的结构】

    1. 最优子结构:就是原问题可以分为多个子问题。
    2. 重复子问题:子问题在计算过程中是重复计算的。

    举例子:斐波那契问题:F(n) = F(n-1) + F (n-2)

    F(n)分为两个子问题:F(n-1)和F(n-2),

    而F(n-1)和F(n-2)重复计算了F(n-2)部分,所以这两个问题就是重复子问题

    重复子问题可以用空间来存储计算过的值,当在计算过程中重复使用的时候就可以在存储表中取值。

    二、例子解析:

    子问题:dp[i][j] 可分为 dp[i][j-1] 和 dp[i-1][j]两个子问题。

    状态方程:dp[i][j] = min(dp[i][j-1],dp[i-1][j]) + grid[i][j]

    • 龙下城游戏dp[i[[j]:如果骑士要走上位置(i,j),并且从该位置选一条最优的路径,最后走到右下角,骑士起码应具备的血量。最终结果为dp[0][0]。

    子问题:dp[i][j+1]、dp[i+1][j]

    状态方程:

    如果骑士向右选择,dp[i][j]_1  = max{ dp[i][j+1] - map[i][j] , 1}     

    如果骑士向下选择,dp[i][j]_2  = max{ dp[i+1][j] - map[i][j] , 1}     

    dp[i][j] = min{ dp[i][j]_1, dp[i][j]_2}

    子问题:邻近的两个:dp[i-1][j-1]、dp[i-1][j]

    状态方程:dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j]

    子问题:dp[i-1][j-1]、dp[i-1][j+1]、dp[i-1][j]

    状态方程:dp[i][j] = min(dp[i-1][j-1], dp[i-1][j+1], dp[i-1][j] ) + A[i][j]

     

    子问题:dp[i-1][j]、dp[i][j-1]

    状态方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]

    状态方程:dp【i】 = min(dp[i-1] , dp[i-2] + nums[i] )

    状态方程:dp[0] = 0,dp[1] = cost[0]

    dp[i] = min(dp[i-1],dp[i-2]) + cost[i]

    • 石子游戏dp[i][j]表示:表示在piles中下标 i 至下标 j 之间的玩家1 所拿石子总数和 玩家2所拿石子总数之差。dp[i][j] > 0 表明玩家1赢,输出True

    状态方程:dp[ i ][ j ] = piles[ i ](初始)

    dp[ i ][ j ] = max( piles[ i ] - dp[ i+1 ][ j ], piles[ j ] - dp[ i ][ j-1 ])

    子问题:dp[i][j] 可分为 dp [j-arr[i]]dp [i-1][j]两个子问题。

    状态方程:dp [i][j] = min( dp [j-arr[i]] +1,dp [i-1][j]

    子问题:dp[i][j] 可分为 dp [j-arr[i]]dp [i-1][j]两个子问题。

    状态方程:dp[i][j] = dp[i][j-arr[i]] + dp[i-1][j]

    • 最长公共子序列:c[i][j]表示(x1,x2....xi) 和 (y1,y2...yj) 的最长公共子序列的长度

    原问题:c[i][j]

    子问题:当两个序列的最后一个元素相等,即Xi =Yj,则❶c[i-1][j-1]   

        否则当 Xi ≠Yj, ❷c[i][j-1]   ❸c[i-1][j]

    状态方程:

    原问题:给定一个数列,长度为N,设 dp[j] 为:以数列中第 j 项结尾的最长递增子序列的长度,求max(dp).

    子问题:对 dp[j] 来讲,dp[0]……dp[j-1] 都是 dp[j] 的子问题

    状态方法:dp(j) = { max(dp(i)) + 1, i<j且L[i]<L[j] }

    • 最长公共子串dp[i][j]用来记录具有这样特点的子串——结尾同时也为子串x1x2⋯xi与y1y2⋯yj的结尾的长度。

    子问题:c[i-1][j-1]

     

    状态方法:

    状态方程:如果s1[i] == s2[j]: dp[i][j] = dp[i-1][j-1]

    否则:dp]i][j] =  dp[i][j] = min(dp[i][j-1] +ord(s2[j-1]),dp[i-1][j] + ord(s1[i-1]),dp[i-1][j-1] + ord(s1[i-1])+ord(s2[j-1]))

    • 最小编辑代价dp[i][j]表示str1[0......i-1]编辑成str2[0......j-1]的最小编辑代价。

    子问题:dp[i][j-1]、dp[i-1][j]、dp[i-1][j-1]

    状态方法:dp[i][j] = min( dp[i][j-1]+icdc+dp[i-1][j]dp[i-1][j-1] + rc 【如果str1[i-1]==str2[j-1],rc = rc,否则,rc = 0】)

    • 交错字符串dp[i][j] 代表是s1的前i个字符与s3中匹配,s2中前j个字符与s3中匹配.

    子问题:dp[i-1][j]、dp[i][j-1]

    状态方法:dp[i][j] = (dp[i-1][j] == True and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] ==True and s2[j-1] == s3[i+j-1])

    状态转移方程:F(n) = min{ F(n-ai) + 1 } 其中ai为小于等于n的完全平方数

    状态方程:dp[i] = dp[i-1] + fi,

      记 f( n )为 [ 0, 10^n )范围内满足条件的数值个数,记 g( k ) 为 k位数中满足条件的数值个数, 则 f(n) = g(1) + g(2) + g(3) + ... +g(n) = f (n - 1) + g (n),

    我们看abcd这个字符串,

    以a为结尾的子字符串为a,dp[0] = 1

    以b为结尾的子字符串为b,ab 。dp[1] = 2

    以c为结尾的子字符串为c,bc,abc。dp[2] = 3

    以d结尾的子字符串有abcd, bcd, cd, d,故 i = 3,dp[3] = 4。

    结果为:1+2+3+4 = 10

    题目可以转换为分别求出以每个字符(a-z为结束字符的最长连续字符串就行了,我们用一个数组res记录下来,最后在求出数组res的所有数字之和就是结果。

    •  n个学生成绩排名,a>b>c……,a>b=c,有多少种排名。dp[j] = (j+1) * (dp[j-1] + dp[j])

  • 相关阅读:
    C++学习笔记十关联容器
    Ubuntu下使用GDB断点Go程序
    各种语言的数字转罗码方法的实现
    为什么 ++i和i++的效果是一样的,试了javascript ,c++ java
    罗马数字转换阿拉伯数字(Java版,考虑较为全面)
    C++学习笔记九顺序容器(二) ForFreeDom 博客园
    智立方 屁话真言108:能盛事者能成事_智立方的杨石头_新浪博客
    腾讯搜搜高管吴军离职的传闻与真相
    罗马数字_百度百科
    快速深入一门语言的几个问题 Shell909090 随笔杂记
  • 原文地址:https://www.cnblogs.com/Lee-yl/p/9974284.html
Copyright © 2011-2022 走看看