• 【动态规划】—— 数字三角形



    动态规划

    动态规划算法把原算法视作若干个重叠子问题的逐层递进,每个子问题的求解过程都构成一个“阶段”。在完成前一个阶段的计算之后,动态规划才会执行下一个阶段的计算。

    为了保证这些计算能够按顺序、不重复地进行,动态规划要求已经求解的子问题不受后续阶段的影响。这个条件也叫“无后效性”。换言之,动态规划对状态空间的遍历构成一张有向无环图,遍历顺序就是该有向无环图的一个拓扑序。有序无环图中的节点对应问题中的“状态”,图中的边则是对应状态之间的“转移”,转移的选取就是动态规划中的“决策”

    在很多情况下,动态规划用于求解最优化问题。此时,下一阶段的最优解应该能够由前前面各阶段的子问题的最优解求出。这个条件被称为“最优子结构性质”。

    “状态”“阶段”“决策”是构成动态规划算法的三要素,而“子问题重叠性”“无后效性”“最优子结构性”是问题能用动态规划求解的三个基本条件。

    动态规划算法把相同的计算过程作用于各阶段的同类子问题,就好像把一个固定的公式套在格式相投的若干输入数据上运行。因此,我们一般只需要定义出DP的计算过程,就可以编程实现了,这个计算过程就称为“状态转移方程”。

    闫式思考法

    集合的角度来思考问题: 


    例题:AcWing 1015. 摘花生


    集合含义:所有从 \small (1,1)  走到 \small (i,j)  的所有路线的最大值 

    在状态计算中,很重要的划分依据:“最后”

    集合的划分依据1.不重 2.不漏(在不重复这一点是,可以出现重复算,因为最后是取子集的最最值)


    AC代码 

    1. #include <iostream>
    2. #include <cstring>
    3. using namespace std;
    4. const int N = 110;
    5. int n, m;
    6. int w[N][N];
    7. int f[N][N];
    8. int main()
    9. {
    10. int T; cin >> T;
    11. while(T -- )
    12. {
    13. scanf("%d%d", &n, &m);
    14. for(int i = 1; i <= n; i ++ )
    15. for(int j = 1; j <= m; j ++ )
    16. scanf("%d", &w[i][j]);
    17. for(int i = 1; i <= n; i ++ )
    18. for(int j = 1; j <= m; j ++ )
    19. f[i][j] = max(f[i][j - 1], f[i - 1][j]) + w[i][j];
    20. cout << f[n][m] << endl;
    21. }
    22. return 0;
    23. }

    例题:AcWing 1018. 最低通行费 


    跟上面的摘花生的是类似的题目类型。多了时间上面的限制( \small \leqslant 2n-1 )

    这个时间上面的限制 等价于 不走回头路

    由于所求的是最小值,这道题在求解的时候需要对边界进行初始化


    AC代码

    1. #include <iostream>
    2. #include <cstring>
    3. using namespace std;
    4. const int N = 210, INF = 0x3f3f3f3f;
    5. int n;
    6. int w[N][N];
    7. int f[N][N];
    8. int main()
    9. {
    10. cin >> n;
    11. for(int i = 1; i <= n; i ++ )
    12. for(int j = 1; j <= n; j ++ )
    13. scanf("%d", &w[i][j]);
    14. for(int i = 1; i <= n; i ++ )
    15. for(int j = 1; j <= n; j ++ )
    16. if(i == 1 && j == 1) f[i][j] = w[i][j];
    17. else
    18. {
    19. f[i][j] = INF;
    20. if(i > 1) f[i][j] = min(f[i][j], f[i - 1][j] + w[i][j]);
    21. if(j > 1) f[i][j] = min(f[i][j], f[i][j - 1] + w[i][j]);
    22. }
    23. cout << f[n][n] << endl;
    24. return 0;
    25. }

    例题:AcWing 1027. 方格取数

    输入样例:

    1. 8
    2. 2 3 13
    3. 2 6 6
    4. 3 5 7
    5. 4 4 14
    6. 5 2 21
    7. 5 6 4
    8. 6 3 15
    9. 7 2 14
    10. 0 0 0

    输出样例:

    67

    这一题相比于前面两题,多了总共走两次这样的限制条件。 

    在只走一次的情况中:

    \small f[i,j] 表示的是 所有从 \small (1,1)  走到 \small (i,j)  的所有路线的最大值 

    \small f[i,j]=max(f[i - 1][j],f[i][j-1]) +w[i][j]

    走两次的情况中:

    \small f[i_1,i_2,j_1,j_2] 表示所有从 \small (1,1)\small (1,1) 走到 \small (i_1,j_1),(i_2,j_2) 的路径的所有集合的最大值

    如何处理“同一个格子不能被重复选择”?

    只有在 \large {\color{Blue} i_1+j_1=i_2+j_2} 时,两条路径的格子才会重合 

    \small k=i_1+j_1=i_2+j_2  表示两个人同时走 k 步(横纵坐标之和)(类比摘花生)

    \small f[k,i_1,i_2] 表示所有从  \small (1,1), \small (1,1) 分别走到 \small (i_1,k-i_1),(i_2,k-i_2) 的路径的最大值


    AC代码 

    1. #include <iostream>
    2. #include <algorithm>
    3. using namespace std;
    4. const int N = 15;
    5. int n;
    6. int w[N][N];
    7. int f[N * 2][N][N];
    8. int main()
    9. {
    10. cin >> n;
    11. int a, b, c;
    12. while(cin >> a >> b >> c, a || b || c) w[a][b] = c;
    13. for(int k = 2; k <= n + n; k ++ )
    14. for(int i1 = 1; i1 <= n; i1 ++ )
    15. for(int i2 = 1; i2 <= n; i2 ++ )
    16. {
    17. int j1 = k - i1, j2 = k - i2;
    18. if(j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
    19. {
    20. int t = w[i1][j1];
    21. if(i1 != i2) t += w[i2][j2];
    22. int &x = f[k][i1][i2];
    23. x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
    24. x = max(x, f[k - 1][i1 - 1][i2] + t);
    25. x = max(x, f[k - 1][i1][i2 - 1] + t);
    26. x = max(x, f[k - 1][i1][i2] + t);
    27. }
    28. }
    29. cout << f[n + n][n][n];
    30. return 0;
    31. }

  • 相关阅读:
    flutter 使用 hive 遇到的错误
    Pytorch 多卡并行(3)—— 使用 DDP 加速 minGPT 训练
    VSCode『SSH』连接服务器『GUI界面』传输
    超越任务调度的极致:初探分布式定时任务 XXL-JOB 分片广播
    SpringBoot Filter过滤器的使用篇
    视频通话中的Camera操作
    CCF ChinaSoft 2023 论坛巡礼|自动驾驶仿真测试论坛
    打印机多张双面打印使用说明
    Kubernetes二进制部署——理论部分
    vue v-model
  • 原文地址:https://blog.csdn.net/forever_bryant/article/details/125430045