跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

路径类动态规划入门:3 道经典例题详解

路径类动态规划基于矩阵网格,通过状态转移求解方案数或最优值。涵盖最小路径和、迷雾森林及过河卒三道典型例题,分别涉及边界初始化、障碍处理与取模运算、以及马步控制点的偏移技巧。重点讲解状态定义、转移方程推导及填表顺序,配合 C++ 代码实现,适合初学者掌握基础 DP 模型。

王初壹发布于 2026/3/20更新于 2026/7/1838 浏览
路径类动态规划入门:3 道经典例题详解

路径类 DP 是线性 DP 的一种,通常在一个 n × m 的矩阵中设定行走规则,研究从起点到终点的方案数、最小路径和或最大路径和等问题。入门阶段的《数字三角形》其实也属于这一范畴。

矩阵的最小路径和

题目描述

路径示意图

思路解析

  1. 状态表示 dp[i][j] 表示从 [1, 1] 格子走到 [i, j] 格子时,所有方案下的最小路径和。

  2. 状态转移方程 考虑最后一步,到达 (i, j) 只能从上方 (i-1, j) 或左方 (i, j-1) 过来。因此取两者的较小值加上当前格子的权值: dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j]

  3. 初始化与边界 填表时需要访问左边和上边的格子,为了避免越界,我们将第 0 行和第 0 列初始化为无穷大。这样在取最小值时永远不会选中它们。同时,将起点 dp[1][1] 初始化为 a[1][1],并在循环中跳过该点,防止被错误覆盖为无穷大。

  4. 填表顺序 从上往下,从左往右。

  5. 输出结果 dp[n][m]

#include <iostream>
#include <cstring>
using namespace std;

const int N = 510;
int n, m;
int a[N][N], dp[N][N];

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
        }
    }

    // 初始化为无穷大
    memset(dp, , (dp));
    dp[][] = a[][];

    
     ( i = ; i <= n; i++) {
         ( j = ; j <= m; j++) {
             (i ==  && j == ) ;
            dp[i][j] = (dp[i - ][j], dp[i][j - ]) + a[i][j];
        }
    }

    cout << dp[n][m] << endl;
     ;
}
0x3f
sizeof
1
1
1
1
// 依序填表
for
int
1
for
int
1
if
1
1
continue
min
1
1
return
0

迷雾森林

题目描述

路径示意图

思路解析

  1. 状态表示 dp[i][j] 表示从 [m, 1] 格子走到 [i, j] 格子时的方案数。

  2. 状态转移方程 规定只能向上或向右走。若当前格子为空地(值为 0),则方案数为左侧和下侧格子方案数之和;若为树(值为 1),则不可达,方案数为 0。 dp[i][j] = dp[i][j - 1] + dp[i + 1][j] (当 a[i][j] == 0)

  3. 初始化 由于数组全局定义默认为 0,无需额外清空。起点 dp[m][1] 设为 1,作为累加的基准。注意填表时跳过起点。

  4. 填表顺序 根据依赖关系,需要从下往上遍历每一行,每行内从左往右。

  5. 输出结果 dp[1][n]

注意:答案需要对 2333 取模。

#include <iostream>
#include <stdio.h>
using namespace std;

const int N = 3010;
const int MOD = 2333;
int m, n;
int a[N][N], dp[N][N];

int main() {
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            scanf("%d", &a[i][j]);
        }
    }

    dp[m][1] = 1;

    for (int i = m; i >= 1; i--) {
        for (int j = 1; j <= n; j++) {
            if (i == m && j == 1) continue;
            if (a[i][j] == 0) {
                dp[i][j] = (dp[i][j - 1] + dp[i + 1][j]) % MOD;
            }
        }
    }

    printf("%d\n", dp[1][n]);
    return 0;
}

过河卒

题目描述

路径示意图

思路解析

本题强制从 [0, 0] 开始,为了方便处理数组越界,我们将输入的坐标统一加 1,相当于棋盘整体平移,从 [1, 1] 开始填表。

  1. 状态表示 dp[i][j] 表示从 [1, 1] 走到 [i, j] 的方案数。

  2. 状态转移方程 卒只能向下或向右移动: dp[i][j] = dp[i][j - 1] + dp[i - 1][j] 仅当目标点不是马的控制点时才执行转移,否则保持 0。

  3. 初始化 dp[1][1] 置为 1。使用方向向量标记马及其控制点(共 9 个点)为障碍,存入 a 数组。

  4. 填表顺序 从左往右,从上往下。

  5. 输出结果 dp[n][m]

注意:方案数可能很大,需使用 long long 类型,数据规模接近阶乘级别。

#include <iostream>
using namespace std;

typedef long long LL;
const int N = 25;
int n, m, c, d;
int a[N][N];
LL dp[N][N];

// 马的八个控制点方向向量
int dx[8] = {2, 2, 1, 1, -1, -1, -2, -2};
int dy[8] = {1, -1, 2, -2, 2, -2, 1, -1};

int main() {
    cin >> n >> m >> c >> d;
    n++, m++, c++, d++; // 坐标偏移

    dp[1][1] = 1;
    // 标记马的控制点
    for (int i = 0; i < 8; i++) {
        if (c + dx[i] >= 1 && c + dx[i] <= n && d + dy[i] >= 1 && d + dy[i] <= m)
            a[c + dx[i]][d + dy[i]] = 1;
    }
    a[c][d] = 1;

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i == 1 && j == 1) continue;
            if (a[i][j] == 0) {
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
            }
        }
    }

    cout << dp[n][m] << endl;
    return 0;
}

这三道题涵盖了路径 DP 中最常见的三种情况:带权最短路、障碍计数以及特殊移动限制。掌握状态定义和转移方程的推导逻辑,比死记硬背代码更重要。在实际调试中,务必注意数组越界和数据溢出问题。

目录

  1. 矩阵的最小路径和
  2. 题目描述
  3. 思路解析
  4. 迷雾森林
  5. 题目描述
  6. 思路解析
  7. 过河卒
  8. 题目描述
  9. 思路解析
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Python 和 Uniapp 的高校科研经费管理系统设计与实现
  • Midreal AI 工具深度解析:交互式小说生成与插图创作实践
  • C++ 二叉搜索树实现详解
  • NumCpp 实战指南:C++ 数值计算库使用教程
  • C++ 数据结构与算法:定义、递归与迭代比较
  • Android 传感器全解:注册监听与常用传感器应用
  • Linux 进程间通信:命名管道(FIFO)实战指南
  • Python 基础语法进阶:条件判断与循环控制
  • Python 自学指南:培养良好编程习惯与避坑建议
  • Web 可访问性最佳实践:构建人人可用的前端界面
  • AI 如何重构智能家居:从指令执行到主动理解
  • 前端大文件处理内存优化实战方案
  • 前端监控最佳实践:错误追踪与性能优化
  • 基于 OpenClaw 部署飞书机器人实战指南
  • C++ 性能优化实战:内存、CPU 与 I/O 效率提升指南
  • Java LangChain4j 框架入门:环境搭建与 AI 服务集成
  • 基于 YOLO 标注格式的无人机航拍人员搜救检测数据集
  • 基于 LLaMA-Factory 微调 Qwen3-VL 视觉模型实战指南
  • 2026 年 3 月 GESP C++ 一级真题:数字替换
  • C++ 异常处理机制详解与避坑指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online