首页 >> 大全

整理动态规划笔记(c 和 cpp 版)

2023-12-16 大全 27 作者:考证青年

爬楼梯 一:动态规划

优化之后的程序

int climbStairs(int n) {int p = 0, q = 0, r = 1;for (int i = 1; i <= n; ++i) {p = q;q = r;r = p + q;}return r;
}

二:矩阵快速幂(参考力扣)

以上的方法适用于 n 比较小的情况,在 n 变大之后,O(n) 的时间复杂度会让这个算法看起来有些捉襟见肘。我们可以用「矩阵快速幂」的方法来优化这个过程

因此我们只要能快速计算矩阵 M的 n 次幂,就可以得到 f(n) 的值。如果直接求取 ,时间复杂度是 O(n) 的,我们可以定义矩阵乘法,然后用快速幂算法来加速这里

如何想到使用矩阵快速幂?

我们可以做这样的变换:

令x

,那么我们又得到了齐次线性递推:

于是就可以使用矩阵快速幂求解了。当然并不是所有非齐次线性都可以化成齐次线性,我们还是要具体问题具体分析。

以下是矩阵快速幂的代码实现

struct Matrix {long long mat[2][2];
};struct Matrix multiply(struct Matrix a, struct Matrix b) {    // 矩阵 a*bstruct Matrix c;for (int i = 0; i < 2; i++) {for (int j = 0; j < 2; j++) {c.mat[i][j] = a.mat[i][0] * b.mat[0][j] + a.mat[i][1] * b.mat[1][j];}}return c;
}struct Matrix matrixPow(struct Matrix a, int n) {    // a 是 f(1) f(2)struct Matrix ret;    // Mret.mat[0][0] = ret.mat[1][1] = 1;ret.mat[0][1] = ret.mat[1][0] = 0;while (n > 0) {if ((n & 1) == 1) {ret = multiply(ret, a);    // ret = ret*a}n >>= 1;    // -->n/2a = multiply(a, a);}return ret;
}int climbStairs(int n) {struct Matrix ret;ret.mat[1][1] = 0;ret.mat[0][0] = ret.mat[0][1] = ret.mat[1][0] = 1;struct Matrix res = matrixPow(ret, n);    // ret 的 n 次方return res.mat[0][0];
}

三:通项公式

之前的方法我们已经讨论了f(n)是齐次线性递推,根据递推方程

,我们可以写出这样的特征方程:

求得

设通解为

,代入初始条件

,得

,我们得到了这个递推数列的通项公式:

接着我们就可以通过这个公式直接求第 n 项了

int climbStairs(int n) {double sqrt5 = sqrt(5);double fibn = pow((1 + sqrt5) / 2, n + 1) - pow((1 - sqrt5) / 2, n + 1);return (int) round(fibn / sqrt5);
}

总结: 矩形盖

仔细观察是斐波拉契问题

某一次的结果可以是由一块叠来的,也可以是由两块小的叠来的

字符串问题

给定一个由0-9组成的字符串,1可以转化成A,2可以转化成B。依此类推。。25可以转化成Y,26可以转化成z,给一个字符串,返回能转化的字母串的有几种?

两种转化方法

矩阵问题:

给一个由数字组成的矩阵,初始在左上角,要求每次只能向下或向右移动,路径和就是经过的数字全部加起来,求可能的最小路径和

分析:我们可以像之前一样,暴力的把每一种情况都试一次,但是依旧会造成过多的重复计算,以本题为例子最后解释一下暴力慢在哪里,以后不再叙述了

从1到6有很多路可走

将A到某个点的最小距离之和填入以下表格

优化空间复杂度(重新开辟一行空间,用来存储步数)

B:9 是 A 的(从左面走过来) ,4 是上面的(从上面走下来的), 1 是这个格子本来的

// 遍历原矩阵
// 初始化
// 
#define MAX_SIZE 100int min(int a, int b) {return a>b?b:a;
}
int minPath(int nums[][4], int numsLine, int numsCol) {// 按道理要分情况int a[MAX_SIZE];int flag = 0;for(int i = 0; i < numsCol; ++i) {a[i] = nums[0][i]+flag;flag = a[i];}for(int i = 1; i < numsLine; ++i) {for(int j = 0; j < numsCol; ++j){if(j)a[j] = min(a[j-1], a[j]);a[j] += nums[i][j];}}return a[numsCol-1];
}

给一个由数字组成的矩阵,初始在左上角,要求每次只能向下或向右移动,路径和就是经过的数字全部加起来,求可能的最大路径和

一个矩阵,初始在左上角,要求每次只能向下或向右移动,求到终点的方法数(将最大最小路径简化了,第一行第一列是1,之后用min计算即可)

代码实现如下

#define MAX_SIZE 100int max(int a, int b) {return a>b?a:b;
}int minWay(int numsLine, int numsCol) {// 按道理要分情况int a[MAX_SIZE];// 计算小的情况就可以了int mAx = max(numsLine, numsCol);int min = numsLine + numsCol - mAx;for(int i = 0; i < min; ++i)a[i] = 1;for(int i = 1; i < mAx; ++i) {for(int j = 1; j < min; ++j){a[j] = a[j-1]+a[j];}}return a[min-1];
}

暗黑字符串:判断字符串纯净还是暗黑(网易17校招)

参考牛客网

刷格子(蓝桥杯)

问题描述 古国的一段古城墙的顶端可以看成 2×N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。 例如下图是一个长度为3,高为2的城墙

你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!) 比如: a d b c e f 就是合格的刷漆顺序。 c e f d a b 是另一种合适的方案。 当已知 N 时,求总的方案数。当n较大时,结果会迅速增大,请把结果对 (十亿零七) 取模。

输入格式:输入数据为一个正整数(不大于1000) 输出格式:输出数据为一个正整数。

样例输入:2 样例输出:24 样例输入:3 样例输出:96 样例输入:22 样例输出:

题解:

从四个顶点出发时

第一步走同一列的另一个格子,然后再向走下一列,并不断重复这个过程。

走完一个直接去下一列,走到最后一列直接返回(有back)

两列两列走,走完一个去下一列,回到上一列,再去下一列

总结:

a[i] = 2*a[i-1]+b[i]+2 *2 *a[i-2];

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了