C++---数字三角形模型---最低通行费(每日一道算法2023.1.14)

该文介绍了一个线性DP问题,商人需从一个N×N的网格左上角走到右下角,每步花费1单位时间,总时间限制为(2N-1),每个格子有不同费用。目标是最小化总费用。通过动态规划,从上、左两个方向计算每个位置的最小费用,最终得到右下角的费用,即最小总费用。
摘要由CSDN通过智能技术生成

注意事项:
本题为线性dp—数字三角形的扩展题。

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

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

输入格式
第一行是一个整数,表示正方形的宽度 N。
后面 N 行,每行 N 个不大于 100 的正整数,为网格上每个小方格的费用。

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

数据范围
1≤N≤100

输入:
5
1  4  6  8  10
2  5  7  15 17
6  8  9  18 20
10 11 12 19 21
20 23 25 29 33
输出:
109
#include <iostream>
#include <cstring>

using namespace std;
const int N = 110;
int n;
int a[N][N], f[N][N];

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

    //初始化DP数组f,使每个元素为最大值,以便后面的计算时比较得出较小的费用
    for (int i = 0; i<=n; i++) memset(f[i], 0x3f3f3f3f, sizeof f[i]);  
    
    //线性DP
    for (int i = 1; i<=n; i++) {
        for (int j = 1; j<=n; j++) {
            if (i == 1 && j == 1) f[1][1] = a[1][1];  //第一个点的费用赋值
            else {
                //如果i>1,则可以从上面走过来,比较上面的路径费用和当前路径费用的大小,并取较小值
                if (i > 1) f[i][j] = min(f[i-1][j] + a[i][j], f[i][j]);
                //如果j>1,则可以从左面走过来,比较左面的路径费用和当前路径费用的大小,并取较小值
                if (j > 1) f[i][j] = min(f[i][j-1] + a[i][j], f[i][j]);
            }
        }
    }

    cout << f[n][n] << endl;  //输出最小费用
    return 0;
}

思路:
经典的线性dp问题,y式dp分析即可

1.状态表示
f[i][j] 表示从起始点到(i, j)点的所有方案费用,属性为Min

2.状态计算
由于有步数限制(2N-1),意味着我们只能从起始点向下或者向右移动,那么在进行dp计算时,对于点(i,j)我们是从这个点的上方和左侧来进行计算,也就是:
f[i][j] = Min(f[i-1][j],f[i][j-1]) + a[i][j]
代码中根据这个来进行一定的小调整即可

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值