• AcWing 1.1 数字三角形模型 dp动态规划


    (1)ACWing 1015. 摘花生 1015. 摘花生 - AcWing题库

    Hello Kitty想摘点花生送给她喜欢的米老鼠。她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。Hello Kitty只能向东或向南走,不能向西或向北走。问Hello Kitty最多能够摘到多少颗花生。

    输入样例: 

    1. 2
    2. 2 2
    3. 1 1
    4. 3 4
    5. 2 3
    6. 2 3 4
    7. 1 6 5

     输出样例:

    1. 8
    2. 16

     

    >>动规五部曲:

    1.确定dp数组以及下标的含义

    • dp[i][j] :为到达 (i , j) 位置的最多能够摘到的花生数,最终所求结果即为 dp[n][m] 

    2.确定递推公式

    • dp[i][j] = max(dp [i][j − 1], dp[i − 1][j]) + w [i][j]

    3.dp 数组初始化

    • dp[i][j]初始化为0

    4.确定遍历顺序

    • 从上到下,从左到右遍历,这样能保证dp[i][j]是经过计算得来的 

    5.举例推导dp数组  

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

    (2)ACWing 1018. 最低通行费(DP)

    ACWing 1018. 最低通行费(原题链接)

    题目描述:一个商人穿过一个 N × N 的正方形的网格,去参加一个非常重要的商务活动。他要从网格的左上角进,右下角出。每穿越中间 1 个小方格,都要花费 1 个单位时间。商人必须在 ( 2 N − 1 )  个单位时间穿越出去。而在经过中间的每个小方格时,都需要缴纳一定的费用。这个商人期望在规定时间内用最少费用穿越出去。请问至少需要多少费用

    注意:不能对角穿越各个小方格(即,只能向上下左右四个方向移动且不能离开网格)

    输入格式:第一行是一个整数,表示正方形的宽度 N。后面 N 行,

                     每行 N 个不大于 100 的正整数,为网格上每个小方格的费用

    输出格式:输出一个整数,表示至少需要的费用

    数据范围:1 ≤ N ≤ 100 

    输入样例: 

    1. 5
    2. 1 4 6 8 10
    3. 2 5 7 15 17
    4. 6 8 9 18 20
    5. 10 11 12 19 21
    6. 20 23 25 29 33

    输出样例:

    109 

    关键信息:时间不超过 (2 N − 1) ,意味着不能走回头路!!!
    发现不能走回头路的性质后就和 ACWing 1015.摘花生 基本一样了,只不过将最大值换成了最小值
    >>动规五部曲:

    1.确定dp数组以及下标的含义

    • dp[i][j] :为到达 (i , j) 位置的最小通行费,最终所求结果即为 dp[n][n] 

    2.确定递推公式

    • dp[i][j] = min (dp[i][j − 1], dp[i − 1][j]) + w [i][j]

    3.dp 数组初始化

    • dp[i][j]初始化为INF
    • dp[0][1]=0;dp[1][0]=0

    4.确定遍历顺序

    • 从上到下,从左到右遍历,这样能保证dp[i][j]是经过计算得来的

    5.举例推导dp数组 

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 110,INF = 1e9;
    5. int n;
    6. int w[N][N];
    7. int dp[N][N];
    8. int main() {
    9. scanf_s("%d", &n);
    10. for (int i = 1; i <= n; i++)
    11. for (int j = 1; j <= n; j++)
    12. scanf_s("%d", &w[i][j]);
    13. memset(dp, 0x3f, sizeof dp);
    14. dp[0][1] = 0; dp[1][0] = 0;
    15. for (int i = 1; i <= n; i++)
    16. for (int j = 1; j <= n; j++) {
    17. dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + w[i][j];
    18. }
    19. printf("%d\n", dp[n][n]);
    20. return 0;
    21. }

    >>知识点回顾:

    (1)最常用的memset赋值

    1. #include 
    2. memset(f, 0, sizeof(f));
    3. 0x3f(正无穷)
    4. -0x3f(负无穷)
    5. memset(f, 0x3f, sizeof(f)); 每个元素大小1,061,109,567
    6. memset(f, -0x3f, sizeof(f)); 每个元素大小-1,044,266,559

    推荐和参考文章: 

    普通数组的memset函数用法详细解读_memset数组-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_43827595/article/details/101452656ACWing 1018. 最低通行费(DP)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzcstxwd/article/details/127530180(3)ACWing 1027.方格取数

    https://www.acwing.com/problem/content/1027/

    设有 NxN 的方格图,我们在其中的某些方格中填入正整数,而其他的方格中则放入数字0,如下图所示:

    某人从图中的左上角A出发,可以向下行走,也可以向右行走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中奖变为数字0)。此人从A点到B点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。

    输入格式:第一行为一个整数N,表示 NxN 的方格图。接下来的每行有三个整数,

                      第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数,

                      一行"0 0 0"表示结束

    输出格式:输出一个整数,表示两条路径上取得的最大的和

    数据范围:N<=10

    输入样例:

    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

    >>思考只走一次和走两次:

    只走一次:f[i,j] 表示所有从(1,1)走到(i,j)的路径的最大值

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

    走两次:f[i1,j1,i2,j2] 表示所有从(1,1),(1,1)分别走到(i1,j1),(i2,j2)路径的最大值。考虑一下两条路线什么时候会走到同一个格子呢?

    这个题有两种思路:

    • 第一种思路:第一个人先走,然后标记一下,接着第二个人再走
    • 第二种思路:同时走

    同时走的话,如何处理“同一个格子不能被重复选择”?

    需要考虑的是什么时候两条路线会有交集呢?必然在同一个格子的时候会有交集。那它们走到同一个格子的时候,这两条路线走过的总步数是一样的。

    • i1+j1==i2+j2 时,两条路径的格子才可能重合

    其中k:k = i1+j1= i2+j2(k表示两条路线当前走到的格子的横纵坐标之和)

    • f[k,i1,i2] 表示所有从(1,1),(1,1)分别走到(i1,k-i1),(i2,k-i2)的路径的最大值

    1. #include
    2. #include
    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. scanf_s("%d", &n);
    10. int a, b, c;
    11. while (cin >> a >> b >> c, a || b || c) w[a][b] = c;
    12. for(int k=2;k<=n+n;k++)
    13. for (int i1 = 1; i1 <= n; i1++)
    14. for (int i2 = 1; i2 <= n; i2++) {
    15. int j1 = k - i1, j2 = k - i2;
    16. if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n) {
    17. int t = w[i1][j1];
    18. if (i1 != i2) t += w[i2][j2];
    19. int& x = f[k][i1][i2];
    20. x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
    21. x = max(x, f[k - 1][i1 - 1][i2] + t);
    22. x = max(x, f[k - 1][i1][i2 - 1] + t);
    23. x = max(x, f[k - 1][i1][i2] + t);
    24. }
    25. }
    26. printf("%d\n", f[n + n][n][n]);
    27. return 0;
    28. }

     知识回顾:“p->q”:① q是p的必要条件; ② p是q的充分条件

  • 相关阅读:
    G1D6-Intriguing properties of neural networks&&&AttacKG&美亚2021
    setInterval倒计时切换页面后不准
    云原生k8s的金箍棒
    第三章-Mybatis源码解析-以xml方式走流程-mapper解析(三)
    测试自学人必看:软件测试如何找测试项目?
    java计算机毕业设计面试刷题系统源码+系统+mysql数据库+lw文档
    Java -- 每日一问:String、StringBuffer、StringBuilder有什么区别?
    C++标准模板(STL)- 类型支持 (数值极限,max_digits10,radix,min_exponent)
    计算机毕业设计ssm+vue基本微信小程序的客户资源管理系统
    景联文科技:高质量数据采集清洗标注服务,助力大语言模型红蓝对抗更加精准高效
  • 原文地址:https://blog.csdn.net/weixin_41987016/article/details/134060263