• 经典动态规划总结


    本文持续更新……

    1 给定两组序列 求上下匹配的最大值(POJ1692 Crossed Matchings)

    题意:给出两行数,求上下匹配的最多组数是多少。

    匹配规则:

    1 匹配对的数字必须相同

    2 每个匹配必须有且只能有一个匹配与之相交叉,且相交叉的两组匹配数字必须不同

    3 一个数最多只能匹配一次

    思路:

    dp[i][j]表示上面取i个数,下面取j个数的最大匹配数

    1)若上面不匹配或下面不匹配,则dp[i][j] = max(dp[i - 1][j], dp[i][j - 1] )

    2)a[i] != b[j], i向左找最大k1使b[j] = a[k1],j向左找最大k2使a[i] = b[k2],

    dp[i][j] = max(dp[i][j], dp[k1 - 1][k2 - 1] + 2 )

    2 过河问题(POJ1700 Crossing River)

    题意:每次过桥的时候最多两个人,如果桥这边还有人,那么还得回来一个人(送手电筒),求最短时间。

    思路:

    首先,每次让最快的人回来是错的。

    先按时间递增排序,dp[i]表示前i个人过河的最短时间

    1)若有i - 1个人过河,则让最快的人将手电筒送回,时间为dp[i - 1] + t[0] + t[i]

    2)若有i - 2个人过河,让最快的人把手电筒送过来,然后第i个人和另外一个人一起过河,由于花费时间最少的人在这边,所以下一次送手电筒过来的一定是花费次少的,送过来后花费最少的和花费次少的一起过河,时间为dp[i - 2] + t[0] + t[i] + 2 * t[1]

    dp[i] = min(dp[i - 1] + t[0] + t[i], dp[i - 2] + t[0] + t[i] + 2 * t[1])

    3 括号匹配问题

    POJ2955 Brackets

    区间dp,dp[i][j]表示从ij匹配的最大数,则

    1)若第i,j可匹配,dp[i][j] = dp[i+1][j-1] + 2

    2)枚举中间点k(i <= k < j), dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j])

    求这两者最大值。

    4 方块消除

    POJ1390 Blocks

    题意:一排带有颜色的砖块,每一个可以消除相同颜色的砖块,,每一次可以到块数k的平方分数,求分数最大值

    思路:dp[i][j][k]表示从第i到第j个段, 并且第j个段后面还有k个不与j相邻但颜色与j相同的方块数。

    记忆化搜索:

    1)i = j, dp[l][r][k] = (len[l] + k) * (len[l] + k)

    2)直接消除,dp[l][r][k] = dfs(l, r - 1, 0) + (len[r] + k) * (len[r] + k)

    否则枚举i(l <= i < r),使第i块与第r颜色块相同,dp[l][r][k] = max(dp[l][r][k], dfs(l, i, len[r] + k) + dfs(i + 1, r - 1, 0))

    5 背包问题(HDU3033 I love sneakers!)

    题意:给定n个集合,每个集合有一定数量的元素,取每个元素有一定的代价和价值,每个集合至少取一个元素,可取多个元素,但每个元素最多取一次,给定总的代价m,求不超过m的情况下最大价值。

    思路:dp[i][j]表示前i个集合,背包容量为j时的最大价值,枚举集合,集合中的每个元素,再枚举背包容量

    1)不取此元素,不变

    2)取此元素,此集合之前未取任何元素,且取此元素或已选过并取此元素

    故状态转移方程如下:

    dp[i][k] = max(dp[i][k], dp[i - 1][k - v] + w, dp[i][k - v] + w )

    状态初始化为:

    dp[0][j] = 0

    dp[i][j] = -INF( i >= 1)

    (集合从1计数)

    6 回文串问题(HDU2205 又见回文)

    题意:给定两个字符串(可能为空串),求这两个串交叉组成新串的子串中的回文串的最大长度。

    布尔型变量dp[i][j][k][l]表示串aijbkl能否组成新串,初始化为false,则采取区间动态规划。(1计数)

    for(int i = 1; i <= la + 1; i++){

                for (int j = 1; j <= lb + 1; j++){

                    dp[i][i][j][j - 1] = dp[i][i - 1][j][j] = dp[i][i - 1][j][j - 1] = 1;

                }

            }

            int ans = 0;

            for(int l1 = 0; l1 <= la; l1++){

                for(int l2 = 0; l2 <= lb; l2++){

                    for(int i = 1, j = i + l1 - 1; j <= la; i++, j++){

                        for(int k = 1, l = k + l2 - 1; l <= lb; k++, l++){

                            if(!dp[i][j][k][l]){

                            bool b1 = i <= j && a[i] == a[j] && dp[i + 1][j - 1][k][l];

                            bool b2 = k <= l && b[k] == b[l] && dp[i][j][k + 1][l - 1];

                            bool b3 = l > 0 && a[i] == b[l] && dp[i + 1][j][k][l - 1];

                            bool b4 = j > 0 && b[k] == a[j] && dp[i][j - 1][k + 1][l];

                            dp[i][j][k][l] = b1 || b2 ||b3 ||b4;

                            }

                            if(dp[i][j][k][l]  && l1 + l2 > ans){

                                ans = l1 + l2;

                            }

                        }

                    }

                }

            }

          

    7 POJ1737 Connected Graph

    题意:给定n个不同标号的顶点,求有多少个不同的无向简单连通图。

    定义f[n]为答案,f[1] = 1, f[2] = 1

    方法1

    将总的数目减去不连通的数目

    总的数目为2 ^ C(n, 2),计算不连通的数目方法如下:

    枚举1号节点所在连通块大小为j(1 <= j < i ),此连通块节点有C(i - 1, j - 1)种选法,1号节点所在连通块有f[j]种形态,剩余i - j个节点有2^C(i - j, 2)种形态。故递推式如下:

    f[i] = 2 ^ C(i, 2) - C(i - 1, j - 1) * f[j] * 2^C(i - j, 2)

    方法2:

    直接求连通的方案数:

    f(n) = (f(k) * f(n - k) * C(n - 2 , k - 1) * ( 2 ^ k - 1)

  • 相关阅读:
    Centos安装mysql
    @autowired注解报错原因及解决办法
    注解@Resource与@Autowired的区别
    SpringBoot三种获取Request和Response的方法
    oss 上传图片、下载 中文名称
    git tags 和 Branches的区别是什么呀,什么时候应该创建一个Tag?
    git使用命令,git checkout -b a 与 git branch a区别
    PostgreSQL-With子句实现递归
    redisson锁 tryLock的使用及正确用法
    mysql any 和in 函数的使用
  • 原文地址:https://www.cnblogs.com/IMGavin/p/5636241.html
Copyright © 2020-2023  润新知