动态规划-求最大下滑累加值

1、题目描述

数字分布呈金字塔形状,从节点下滑过程中累加对应的数值,在任意一个节点,可往左下滑,也可以往右下滑,求最大下滑累加值。

 2、解决思路

算法:动态规划

决策:左下滑、右下滑

状态:下滑累加值、访问状态

按照金字塔结构,划分为多层,每层的节点数量为k个(k为当前层数),节点的值保存在一个一维数组pyramid[n]中,n为节点总数。

如何遍历每一层的节点?

节点索引值i与节点所在层数n的关系

i=\frac{n(n+1)}{2}

当前节点往左下滑,下层节点与当前节点索引的关系

i_{next} = i_{cur}+n(n为当前层数)

当前节点往右下滑,下层节点与当前节点索引的关系

i_{next} = i_{cur}+n+1(n为当前层数)

利用两个状态数组记录下滑过程中当前层的状态:

  • 记录节点当前累计值(即下滑过程中的累加值)
  • 记录节点是否已访问

当达到最后一层时,即可得到最大值,因此,只需要在最后一层中遍历所有节点累加值就可以得到最大下滑累加值。

3、代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int get_pyramid_index(int r, int j);
int get_left_node_index(int r, int idx);
int get_right_node_index(int r, int idx);
void set_node_state(int state[], int pyramid[], int visited[], int idx1, int idx2);

// Memory model of `pyramid`:
// `pyramid` is a one-dimensional array containing the elements of a pyramid with `rows` levels,
// in direct succession from left to right, top to bottom
int pyramid_slide_down(int num_elements, const int pyramid[num_elements], int rows) 
{
    int largest = 0;
    int *state = NULL;
    int *visited = NULL;
    int r = 0, i = 0;
    int idx = 0;
    int idx_l = 0, idx_r = 0;

    if(1 == num_elements || 1 == rows)
    {
        return pyramid[0];
    }

    state = (int*)malloc(num_elements * sizeof(int)); // 记录节点当前总值状态
    visited = (int*)malloc(num_elements * sizeof(int)); // 记录节点访问状态

    memset(state, 0, num_elements * sizeof(int));
    memset(visited, 0, num_elements * sizeof(int));

    state[0] = pyramid[0];
    visited[0] = 1; // 已访问

    for(r = 1; r < rows; r++)  // 遍历层数
    {
        // 决策:往左下滑
        for(i = 0; i < r; i++)  // 遍历每一层的数据
        {
            idx = get_pyramid_index(r, i); // 得到本层节点在pyramid数组的索引
            idx_l = get_left_node_index(r, idx); // 得到左子节点在pyramid数组的索引

            set_node_state(state, pyramid, visited, idx, idx_l);
        }

        // 决策:往右下滑
        for(i = 0; i < r; i++)  // 遍历每一层的数据
        {
            idx = get_pyramid_index(r, i);
            idx_r = get_right_node_index(r, idx);

            set_node_state(state, pyramid, visited, idx, idx_r);
        }
    }

    // 在最后一层中寻找最大值
    largest = state[num_elements - 1];
    for(i = num_elements - 1; i > num_elements - rows - 1; i--)
    {
        if(state[i] > largest)
        {
            largest = state[i];
        }
    }

    free(state);
    free(visited);

    return largest;
}

int get_pyramid_index(int r, int i)
{
    return(i + (r*(r-1))/2);
}

int get_left_node_index(int r, int idx)
{
    return(idx + r);
}

int get_right_node_index(int r, int idx)
{
    return(idx + r + 1);
}

void set_node_state(int state[], int pyramid[], int visited[], int idx1, int idx2)
{
    int tmp_state = state[idx1] + pyramid[idx2];

    if(visited[idx2] == 0)  // 未访问过
    {
        state[idx2] = tmp_state;
        visited[idx2] = 1;
    }
    else
    {
        // 只有当值比之前的值大时,才替换,确保最后结果为最大值
        if(tmp_state > state[idx2])
        {
            state[idx2] = tmp_state;
        }
    }

    return ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值