当前位置: 首页 > wzjs >正文

购物类网站建设网站推广的技巧

购物类网站建设,网站推广的技巧,进一步推进政府网站集约化建设,网站建设公司i在C的动态规划中,选择一维或二维DP表的核心依据是 状态变量的数量 和 状态转移的依赖关系。以下是清晰的判断逻辑和具体场景分析: 一、一维DP表 适用条件 单个状态变量:问题仅需一个参数定义状态(例如:数组下标、时间…

        在C++的动态规划中,选择一维或二维DP表的核心依据是 状态变量的数量 和 状态转移的依赖关系。以下是清晰的判断逻辑和具体场景分析:


一、一维DP表

适用条件

  1. 单个状态变量:问题仅需一个参数定义状态(例如:数组下标、时间步、容量等)。

  2. 线性依赖:当前状态仅依赖于 前序的少数状态(如dp[i]依赖dp[i-1]dp[i-2])。

典型问题

  1. 斐波那契数列

    int fib(int n) {// 边界条件:如果n小于等于1,直接返回n// 因为斐波那契数列的第0项是0,第1项是1if (n <= 1) return n;// 定义一个大小为n+1的一维数组dp,用于存储斐波那契数列的值// dp[i]表示第i个斐波那契数vector<int> dp(n+1);// 初始化dp数组的前两项// dp[0] = 0:斐波那契数列的第0项是0// dp[1] = 1:斐波那契数列的第1项是1dp[0] = 0; dp[1] = 1;// 从第2项开始,逐个计算斐波那契数列的值for (int i=2; i<=n; i++) // 状态转移方程:当前项等于前两项之和// dp[i] = dp[i-1] + dp[i-2]dp[i] = dp[i-1] + dp[i-2];// 返回第n个斐波那契数return dp[n];
    }
  2. 爬楼梯问题(每次爬1或2步):

    int climbStairs(int n) {// 定义一个大小为n+1的一维数组dp,用于存储爬楼梯问题的解// dp[i]表示爬到第i阶楼梯的方法数vector<int> dp(n+1);// 初始化dp数组的前两项// dp[0] = 1:爬到第0阶楼梯的方法数为1(理解为起点)// dp[1] = 1:爬到第1阶楼梯的方法数为1(只有一种方式:爬1步)dp[0] = 1; dp[1] = 1;// 从第2阶开始,逐个计算爬到每阶楼梯的方法数for (int i=2; i<=n; i++)// 状态转移方程:爬到第i阶楼梯的方法数等于爬到第i-1阶和第i-2阶的方法数之和// 因为每次可以爬1步或2步dp[i] = dp[i-1] + dp[i-2];// 返回爬到第n阶楼梯的方法数return dp[n];
    }
  3. 0-1背包问题(空间优化版)(注意:原始0-1背包是二维,但可用一维优化):

    int knapsack(vector<int>& weights, vector<int>& values, int capacity) {// 定义一个大小为capacity+1的一维数组dp,初始化为0// dp[j]表示背包容量为j时的最大价值vector<int> dp(capacity + 1, 0);// 遍历每个物品for (int i=0; i<weights.size(); i++) // 逆序遍历背包容量,从最大容量到当前物品的重量// 逆序更新是为了确保每个物品只被使用一次(0-1背包问题)for (int j=capacity; j>=weights[i]; j--) // 状态转移方程:选择是否将当前物品放入背包// dp[j]表示不放入当前物品时的最大价值// dp[j - weights[i]] + values[i]表示放入当前物品时的最大价值dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);// 返回背包容量为capacity时的最大价值return dp[capacity];
    }

二、二维DP表

适用条件

  1. 两个状态变量:问题需要两个参数定义状态(例如:两个序列的索引、二维坐标等)。

  2. 多维依赖:当前状态依赖多个方向的状态(如左、上、左上等)。

典型问题

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

    int lcs(string& s1, string& s2) {// 获取两个字符串的长度int m = s1.size(), n = s2.size();// 定义一个大小为(m+1) x (n+1)的二维数组dp,初始化为0// dp[i][j]表示s1的前i个字符和s2的前j个字符的最长公共子序列长度vector<vector<int>> dp(m+1, vector<int>(n+1, 0));// 遍历s1的每个字符for (int i=1; i<=m; i++) {// 遍历s2的每个字符for (int j=1; j<=n; j++) {// 如果当前字符相等if (s1[i-1] == s2[j-1]) // 状态转移方程:当前字符相等时,LCS长度加1dp[i][j] = dp[i-1][j-1] + 1;else // 状态转移方程:当前字符不相等时,取左边或上边的最大值dp[i][j] = max(dp[i-1][j], dp[i][j-1]);}}// 返回s1和s2的最长公共子序列长度return dp[m][n];
    }
  2. 编辑距离

    int minDistance(string s1, string s2) {// 获取两个字符串的长度int m = s1.size(), n = s2.size();// 定义一个大小为(m+1) x (n+1)的二维数组dp,初始化为0// dp[i][j]表示将s1的前i个字符转换为s2的前j个字符所需的最小操作数vector<vector<int>> dp(m+1, vector<int>(n+1, 0));// 初始化dp表的第一列:将s1的前i个字符转换为空字符串需要i次删除操作for (int i=0; i<=m; i++) dp[i][0] = i;// 初始化dp表的第一行:将空字符串转换为s2的前j个字符需要j次插入操作for (int j=0; j<=n; j++) dp[0][j] = j;// 遍历s1的每个字符for (int i=1; i<=m; i++) {// 遍历s2的每个字符for (int j=1; j<=n; j++) {// 如果当前字符相等if (s1[i-1] == s2[j-1]) // 状态转移方程:当前字符相等时,不需要操作,直接继承dp[i-1][j-1]dp[i][j] = dp[i-1][j-1];else // 状态转移方程:当前字符不相等时,取插入、删除、替换操作的最小值,并加1dp[i][j] = 1 + min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]});}}// 返回将s1转换为s2所需的最小操作数return dp[m][n];
    }
  3. 矩阵路径问题(带障碍物)

    int uniquePathsWithObstacles(vector<vector<int>>& grid) {// 获取网格的行数和列数int m = grid.size(), n = grid[0].size();// 定义一个大小为m x n的二维数组dp,初始化为0// dp[i][j]表示从起点(0,0)到点(i,j)的路径数量vector<vector<int>> dp(m, vector<int>(n, 0));// 初始化起点(0,0)的路径数量// 如果起点不是障碍物(grid[0][0] == 0),则dp[0][0] = 1,否则为0dp[0][0] = grid[0][0] == 0 ? 1 : 0;// 遍历网格的每个点for (int i=0; i<m; i++) {for (int j=0; j<n; j++) {// 如果当前点是障碍物,跳过if (grid[i][j] == 1) continue;// 如果上方有格子(i>0),则从上方格子到达当前点的路径数累加到dp[i][j]if (i>0) dp[i][j] += dp[i-1][j];// 如果左方有格子(j>0),则从左方格子到达当前点的路径数累加到dp[i][j]if (j>0) dp[i][j] += dp[i][j-1];}}// 返回到达终点(m-1,n-1)的路径数量return dp[m-1][n-1];
    }

三、如何快速判断维度?

  1. 分析问题的状态定义

    • 若问题需要同时跟踪 两个独立的变量(如两个字符串的位置、二维坐标),用二维。

    • 若问题只需一个变量(如时间、容量),用一维。

  2. 观察状态转移方程

    • 若转移方程涉及 dp[i][j] 依赖 dp[i-1][j-1] 或 dp[i][j-1],必须用二维。

    • 若转移方程仅依赖 dp[i-1] 或 dp[i-2],可以尝试一维。

  3. 特殊情况

    • 有些二维问题可以通过 滚动数组 优化为一维(如0-1背包)。

    • 但若状态依赖关系复杂(如需要左上角的值),则无法优化。


四、总结

维度适用场景示例问题状态依赖
一维DP单一状态变量,线性依赖斐波那契、爬楼梯、0-1背包优化dp[i]依赖dp[i-1]
二维DP两个状态变量,多维依赖LCS、编辑距离、矩阵路径dp[i][j]依赖左、上、左上

五、一维DP表示例:斐波那契数列

#include <iostream>
#include <vector>
using namespace std;int fibonacci(int n) {if (n <= 1) return n; // 边界条件:斐波那契数列的前两项为0和1vector<int> dp(n + 1, 0); // 定义一维DP表,dp[i]表示第i个斐波那契数dp[0] = 0; // 初始化第0项dp[1] = 1; // 初始化第1项for (int i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2]; // 状态转移方程:当前项等于前两项之和}return dp[n]; // 返回第n项的结果
}int main() {int n = 10;cout << "Fibonacci(" << n << ") = " << fibonacci(n) << endl; // 输出结果return 0;
}

代码解析

  1. 边界条件

    • 斐波那契数列的前两项是固定的:dp[0] = 0dp[1] = 1

    • 如果n <= 1,直接返回n,避免不必要的计算。

  2. DP表定义

    • vector<int> dp(n + 1, 0):定义一个大小为n+1的一维数组,初始值为0。

    • dp[i]表示第i个斐波那契数。

  3. 状态转移方程

    • dp[i] = dp[i - 1] + dp[i - 2]:当前项等于前两项之和。

    • 这是斐波那契数列的核心递推关系。

  4. 空间优化

    • 由于dp[i]只依赖于dp[i-1]dp[i-2],可以进一步优化为只使用两个变量,而不是整个数组。


六、二维DP表示例:最长公共子序列(LCS)

#include <iostream>
#include <vector>
#include <string>
using namespace std;int lcs(string& s1, string& s2) {int m = s1.size(), n = s2.size(); // 获取两个字符串的长度vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // 定义二维DP表,dp[i][j]表示s1[0..i-1]和s2[0..j-1]的LCS长度for (int i = 1; i <= m; i++) { // 遍历s1的每个字符for (int j = 1; j <= n; j++) { // 遍历s2的每个字符if (s1[i - 1] == s2[j - 1]) { // 如果当前字符相等dp[i][j] = dp[i - 1][j - 1] + 1; // 状态转移:LCS长度加1} else { // 如果当前字符不相等dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); // 状态转移:取左边或上边的最大值}}}return dp[m][n]; // 返回最终结果
}int main() {string s1 = "abcde";string s2 = "ace";cout << "LCS length: " << lcs(s1, s2) << endl; // 输出结果return 0;
}

代码解析

  1. DP表定义

    • vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)):定义一个大小为(m+1) x (n+1)的二维数组,初始值为0。

    • dp[i][j]表示字符串s1的前i个字符和s2的前j个字符的最长公共子序列长度。

  2. 状态转移方程

    • 如果s1[i-1] == s2[j-1],则dp[i][j] = dp[i-1][j-1] + 1

    • 如果s1[i-1] != s2[j-1],则dp[i][j] = max(dp[i-1][j], dp[i][j-1])

  3. 初始化

    • dp[0][j]dp[i][0]都初始化为0,因为空字符串与任何字符串的LCS长度为0。

  4. 遍历顺序

    • 外层循环遍历s1,内层循环遍历s2,确保每个子问题都被正确计算。

  5. 结果

    • dp[m][n]即为两个字符串的最长公共子序列长度。


七、动态规划的核心知识点

  1. 状态定义

    • 明确dp[i]dp[i][j]表示什么。例如:

      • 斐波那契数列:dp[i]表示第i个斐波那契数。

      • LCS问题:dp[i][j]表示s1[0..i-1]s2[0..j-1]的最长公共子序列长度。

  2. 状态转移方程

    • 描述当前状态与之前状态的关系。例如:

      • 斐波那契数列:dp[i] = dp[i-1] + dp[i-2]

      • LCS问题:dp[i][j] = dp[i-1][j-1] + 1(如果字符相等),否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])

  3. 初始化

    • 根据问题的边界条件初始化DP表。例如:

      • 斐波那契数列:dp[0] = 0dp[1] = 1

      • LCS问题:dp[0][j] = 0dp[i][0] = 0

  4. 遍历顺序

    • 确保在计算dp[i][j]时,所依赖的状态已经计算完成。

  5. 空间优化

    • 如果状态转移只依赖于有限的前几个状态,可以优化空间复杂度。例如:

      • 斐波那契数列:用两个变量代替整个数组。

      • 0-1背包问题:用一维数组代替二维数组。


八、总结

  • 一维DP表:适用于状态变量单一、依赖关系简单的问题(如斐波那契数列、爬楼梯问题)。

  • 二维DP表:适用于状态变量有两个、依赖关系复杂的问题(如LCS、编辑距离)。

  • 核心步骤:定义状态、写出状态转移方程、初始化、确定遍历顺序、优化空间(可选)。

http://www.dtcms.com/wzjs/194764.html

相关文章:

  • 网易企业邮箱注册入口官网网站关键词优化推广哪家好
  • 智能管理系统定制开发惠州seo推广外包
  • 云盘做网站空间2345网址大全
  • 宁夏固原住房和建设局网站武汉seo
  • 免费的行情软件下载纵横seo
  • 怎样做农产品交易平台网站百度指数十年
  • 沈阳设计网站公司网站奇葩网站100个
  • 给wordpress网站做ssl卸载培训心得体会范文500字
  • 东莞网站建设设网站源码
  • 青岛网站建设软件下载搜易网优化的效果如何
  • 郑州今天出啥大事儿了求职seo服务
  • 做软装找图片的网站yandex网站推广
  • 纪委建设网站的意义青岛网站建设哪家好
  • 网站备案的要求是什么百度竞价排名是哪种方式
  • flex做的网站标题优化seo
  • 切片工具做网站怎么做开封网站优化公司
  • 怎么自建网站深圳百度推广公司
  • apache搭建网站网站快速排名服务商
  • 劳务派遣做网站有必要吗武汉百度推广电话
  • 视频制作流程广西网站seo
  • 精品课程网站开发免费网站代理访问
  • 做图片的网站百度一下你就知道 官网
  • 门户网站跳出率徐州seo公司
  • 徐州有哪些制作网站的公司吗进入百度首页
  • 常州做网站公司有哪些海淀区seo搜索优化
  • 广州新型病毒最新情况娄底seo
  • 河北城乡住房建设厅网站关键词排名软件官网
  • 大连做网站那个公司最好网络营销理论包括哪些
  • 动态网站开发简单例子国外网站谷歌seo推广
  • 免费网站建设php微信怎么推广