数字三角形相关问题

博客围绕C++语言,探讨了动态规划算法在几个问题中的应用,包括摘花生、最低通行费、方格取数和传纸条。介绍了摘花生的状态转移方程及复杂度,指出最低通行费状态转移类似,方格取数需两人同时走枚举状态,传纸条可复用方格取数代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

摘花生

状态转移方程:

f[i][j] = max(f[i][j-1],f[i-1][j])+a[i][j];

复杂度 一共有n*n个状态 每个状态由两个转移,时间复杂度O(n2),但是题目中有多个输入,所以接近极限时间了。

#include <iostream>
using namespace std;
const int N = 1e2+10;
int f[N][N];
int a[N][N];
int main() {
    int n;
    cin>>n;
    while(n--){
        int r,c;
        scanf("%d%d",&r,&c);
        for(int i = 1;i<=r;i++){
            for(int j = 1;j<=c;j++){
                scanf("%d",&a[i][j]);
            }
        }
        for(int i = 1;i<=r;i++){
            for(int j = 1;j<=c;j++){
                f[i][j] = max(f[i-1][j],f[i][j-1])+a[i][j];
            }
        }
        cout<<f[r][c]<<endl;
    }


    return 0;
}

最低通行费

状态转移同上,只是max改min,但是需要初始化

#include <iostream>
using namespace std;
const int N = 1e2+10;
int f[N][N];
int a[N][N];
int main() {
    int n;
    cin>>n;
        for(int i = 1;i<=n;i++){
            for(int j = 1;j<=n;j++){
                scanf("%d",&a[i][j]);
            }
        }
        for(int i = 1;i<=n;i++) {
            f[i][1] = f[i-1][1]+a[i][1];
            f[1][i] = f[1][i-1]+a[1][i];
        }
        for(int i = 2;i<=n;i++){
            for(int j = 2;j<=n;j++){
                f[i][j] = min(f[i-1][j],f[i][j-1])+a[i][j];
                // cout<<f[i][j]<<' ';
            }
            // cout<<endl;
        }
        cout<<f[n][n]<<endl;
    


    return 0;
}

方格取数

思路:
可以想象两个人一起走,然后最后当两个人走到B点的时候就是答案,每次两个人一起走的时候要枚举四种状态,然后取最大值。
代码中状态转移写的很清楚:

#include <iostream>
using namespace std;
const int N = 15;
int f[2*N][N][N];
int a[N][N];
int main() {
    int n;
    cin>>n;
    int x,y;
    scanf("%d%d",&x,&y);
    while(x&&y){
        cin>>a[x][y];
        scanf("%d%d",&x,&y);
    }

    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=n;j++){
            for(int k = 2;k<=2*n;k++){//k的枚举外面还是里面都不会有影响
                if(k-i>=1&&k-i<=n&&k-j>=1&&k-j<=n){
                    if(i==j){
                        f[k][i][j] = a[i][k-i];
                    }
                    else f[k][i][j] = a[i][k-i]+a[j][k-j];
                    int maxx = -0x3f3f3f3f;
                    maxx = max(maxx,f[k-1][i][j]);
                    maxx = max(maxx,f[k-1][i-1][j]);
                    maxx = max(maxx,f[k-1][i][j-1]);
                    maxx = max(maxx,f[k-1][i-1][j-1]);
                    f[k][i][j] +=maxx;
                }
            }
        }
    }
    cout<<f[2*n][n][n];


    return 0;
}

传纸条

题目中与上一题目有不同之处:不能重复走一个格子,但是在最优答案中一定不会走同一个格子,就算能够走同一个各自,那么说明周围的点的值都是0,走别的都一样,所以最后的答案一定是正确的,可用上面题目的coding。

代码:

#include <iostream>
using namespace std;
const int N = 55;
int f[2*N][N][N];
int a[N][N];
int main() {
    int n,m;
    cin>>n>>m;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++)
            cin>>a[i][j];
    }

    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=n;j++){
            for(int k = 2;k<=n+m;k++){
                if(k-i>=1&&k-i<=m&&k-j>=1&&k-j<=m){
                    if(i==j){
                        f[k][i][j] = a[i][k-i];
                    }
                    else f[k][i][j] = a[i][k-i]+a[j][k-j];
                    int maxx = -0x3f3f3f3f;
                    maxx = max(maxx,f[k-1][i][j]);
                    maxx = max(maxx,f[k-1][i-1][j]);
                    maxx = max(maxx,f[k-1][i][j-1]);
                    maxx = max(maxx,f[k-1][i-1][j-1]);
                    f[k][i][j] +=maxx;
                }
            }
        }
    }
    cout<<f[m+n][n][n];


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值