数据结构之动态规划(三) | 礼物的最大值(剑指offer47)python+matlab

1. 礼物问题

就是从左上角到右下角,中间经过的权重选择要是最大的,最后路径权重的累加和是所有可能情况里面最大的,有图论的意思在里面了。
在这里插入图片描述

2. 求出最大值

2.1 Matlab

% 题目来源:剑指 Offer 47: 礼物的最大价值
    M = [5 1 5 1;
         3 5 3 5;
         4 2 1 1;
         1 5 1 3;
         1 5 3 4];

function f = max_gift_value1(M)
    % 输入的M就是棋盘中每个礼物的价值
    [m,n] = size(M);  % 棋盘m行n列
    FF = M;  % 初始化DP数组和M完全相同,用来保存f(i,j)
    % 计算FF的第一列
    FF(:,1) = cumsum(M(:,1));  % cumsum函数用来计算累加和
    % 计算FF的第一行
    FF(1,:) = cumsum(M(1,:));
    % 循环计算右下部分的元素
    for i = 2:m
        for j = 2:n
            tem1 = FF(i,j-1) + M(i,j);  % 从左边来
            tem2 = FF(i-1,j) + M(i,j);  % 从上面来
            FF(i,j) = max(tem1,tem2); 
        end
    end
    f = FF(m,n);%累加的最后一个总和
end



>>>>>>>>>>>>>>>>输出>>>>>>>>>>>>>>>>>>>>
f =

    32

2.2 Python

import numpy as np
matrix= np.array([[5,1,5,1],
                 [3,5,3,5],
                 [4,2,1,1],
                 [1,5,1,3],
                 [1,5,3,4]],
                dtype=int)
a,b=matrix.shape
Matrix=matrix
Matrix[:,0]=np.cumsum(Matrix[:,0],axis=0,dtype=int)
Matrix[0,:]=np.cumsum(Matrix[0,:],axis=0,dtype=int)

i=0
j=0
for i in range(1,a):
    for j in range(1,b):
        num1 = Matrix[i][j]+Matrix[i-1][j]#left
        num2 = Matrix[i][j]+Matrix[i][j-1]#up
        Matrix[i][j]=max(num1,num2)

print("最大值是", Matrix[a-1][b-1])
print("整个矩阵是",Matrix)

##############输出###############
最大值是 32

整个矩阵是 
[[ 5  6 11 12]
 [ 8 13 16 21]
 [12 15 17 22]
 [13 20 21 25]
 [14 25 28 32]]
#############################

3. 求出路径

3.1 Matlab

function [f,path] = max_gift_value2(M)
    % 输入的M就是棋盘中每个礼物的价值
    [m,n] = size(M);  % 棋盘m行n列
    FF = M;  % 初始化DP数组和M完全相同,用来保存f(i,j)
    % 计算FF的第一列
    FF(:,1) = cumsum(M(:,1));  % cumsum函数用来计算累加和
    % 计算FF的第一行
    FF(1,:) = cumsum(M(1,:));
    % 循环计算右下部分的元素
    for i = 2:m
        for j = 2:n
            tem1 = FF(i,j-1) + M(i,j);  % 从左边来
            tem2 = FF(i-1,j) + M(i,j);  % 从上面来
            FF(i,j) = max(tem1,tem2);
        end
    end
    f = FF(m,n);
    
    % 根据程序中得到的DP数组(FF)来推出对应的路径path
    path = zeros(m,n);  % path全为01组成,1表示经过该格子
    i = m; j = n;
    
    while i ~= 1 || j ~= 1  % 只要没有回到原点
        path(i,j) = 1;  % 把path矩阵的第i行第j列变成1(表示访问了这个格子)
        
        if i == 1 % 如果到了第一行
            path(1,1:j) = 1;  % 剩余的路径沿着左边一直走就可以了
            break  % 退出循环
        end
        
        if j == 1 % 如果到了第一列
            path(1:i,1) = 1;  % 剩余的路径沿着上方一直走就可以了
            break    % 退出循环
        end
        
        tmp1 = FF(i-1,j); % 上方单元格FF的值
        tmp2 = FF(i,j-1); % 左边单元格FF的值
        ind = find([tmp1,tmp2] == (FF(i,j)-M(i,j)),1);  % 看哪个值等于FF(i,j)-M(i,j)
        if ind == 1 % 如果上方单元格FF的值等于FF(i,j)-M(i,j)
            i = i-1;  % 说明上一步沿着上方来的
        else  % 如果左边单元格FF的值等于FF(i,j)-M(i,j)
            j = j-1; % 说明上一步沿着左边来的
        end
    end   
end

3.2 Python

import numpy as np
matrix= np.array([[5,1,5,1],
                 [3,5,3,5],
                 [4,2,1,1],
                 [1,5,1,3],
                 [1,5,3,4]],
                dtype=int)
a,b=matrix.shape
Matrix=matrix.copy()
Matrix[:,0]=np.cumsum(Matrix[:,0],axis=0,dtype=int)
Matrix[0,:]=np.cumsum(Matrix[0,:],axis=0,dtype=int)

i=0
j=0
for i in range(1,a):
    for j in range(1,b):
        num1 = Matrix[i][j]+Matrix[i-1][j]#left
        num2 = Matrix[i][j]+Matrix[i][j-1]#up
        Matrix[i][j]=max(num1,num2)

print("最大值是", Matrix[a-1][b-1])
print("整个矩阵是", Matrix)

i=a
j=b
path= np.zeros((a,b))
while i!=0 and j!=0:
    
    path[i-1][j-1]=1
    
    if i==0:
        path[0][0:j]=1
        break

    if j==0:
        path[0:i][0]=1
        break

    tmp1 = Matrix[i-2][j-1] #up
    tmp2 = Matrix[i-1][j-2] #left
    
    if Matrix[i-1][j-1] - matrix[i-1][j-1] == tmp1:
        i=i-1
    else:
        j=j-1
print(path)

>>>>>>>>>>输出>>>>>>>>>>>>>>>>>>>>>>>
>#总和最大权重的路径为
>array([[1., 0., 0., 0.],
       [1., 1., 0., 0.],
       [0., 1., 0., 0.],
       [0., 1., 0., 0.],
       [0., 1., 1., 1.]])    
       
	

4.总结

求最大值的时候是顺序的,求路径得先求出累加和再反向推出路径,用累加后的矩阵的相邻两个值相减,看是否值跟原矩阵相等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值