[动态规划]矩阵取数游戏

这篇具有很好参考价值的文章主要介绍了[动态规划]矩阵取数游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

矩阵取数游戏

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n行*m列的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有的元素;
2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
3. 每次取数都有一个得分值,为每行取数的得分之和;每行取数的得分 = 被取走的元素值*i,其中i表示第i次取数(从1开始编号);
4. 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

关于输入

包括n+1行;
第一行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开
l<=n,m<=80,1<=aij<=1000

关于输出

仅包含1行,为一个整数,即输入矩阵取数后的最大的分。

例子输入
2 3
1 2 3
3 4 2
例子输出
34
解题分析

这个问题的具体描述是:给定一个n行m列的矩阵,每次从每行中取走一个元素(只能是行首或行尾的元素),每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*i,其中i表示第i次取数。求取数后的最大得分。

程序的主要思路如下:

1. 首先,程序读取两个整数n和m,然后读取n行m列的矩阵,存储在数组`a`中。

2. 然后,程序对每一行进行处理。对于每一行,程序初始化一个二维数组`dp`,`dp[i][j]`表示从第i个元素到第j个元素(包括i和j)的子数组中,取数的最大得分。

3. 程序遍历所有可能的子数组长度(从1到m)。对于每一个子数组长度,程序遍历所有可能的子数组的起始位置。

   - 如果子数组长度为1,那么`dp[i][j]`就等于`m * a[row][i]`,因为子数组只有一个元素,所以取数的得分就是`m * a[row][i]`。

   - 如果子数组长度大于1,那么`dp[i][j]`就等于`dp[i+1][j] + (m-len+1) * a[row][i]`和`dp[i][j-1] + (m-len+1) * a[row][j]`中的较大值。这是因为,我们可以选择取第i个元素或者第j个元素,所以我们需要比较这两种选择的得分,取较大的那个。

4. 对于每一行,`dp[0][m-1]`就是这一行的最大得分。程序将所有行的最大得分累加起来,就得到了总的最大得分。

这个程序的时间复杂度是O(n*m^2),因为它需要对每一行遍历所有可能的子数组。如果矩阵的大小非常大,那么这个程序可能会运行得比较慢。

代码实现
#include <iostream>
#include <cstring>
using namespace std;

int dp[85][85];
int a[85][85];


int main() {
    int n,m; cin>>n>>m;
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
            cin>>a[i][j];
        }
    for(int row=0;row<n;row++){
        memset(dp,0,sizeof(dp));
        for(int len=1;len<=m;len++)
            for(int i=0;i<m && i+len-1<m;i++){
                int j=i+len-1;
                if(len==1){
                    dp[i][j]=m*a[row][i];
                }
                else{
                    dp[i][j]=max(dp[i+1][j]+(m-len+1)*a[row][i],dp[i][j-1]+(m-len+1)*a[row][j]);
                }
            }
        ans+=dp[0][m-1];
    }
    cout<<ans<<endl;
	return 0;
}
当然,使用记忆搜索法也不错

这个程序是用来解决“矩阵取数游戏”问题的改进版本。它仍然使用了动态规划的思想,但是采用了记忆化搜索的方法,将递归的过程中重复的子问题的解存储起来,避免了重复计算,从而提高了效率。

程序的主要思路如下:

1. 首先,程序读取两个整数n和m,然后读取n行m列的矩阵,存储在数组`a`中。

2. 然后,程序对每一行进行处理。对于每一行,程序使用一个记忆化搜索的函数`f(i, j)`来计算从第i个元素到第j个元素(包括i和j)的子数组中,取数的最大得分。

3. 函数`f(i, j)`的定义如下:

   - 如果`dp[i][j]`已经计算过,那么直接返回`dp[i][j]`的值。

   - 如果`i`等于`j`,那么`dp[i][j]`就等于`m * a[row][i]`,因为子数组只有一个元素,所以取数的得分就是`m * a[row][i]`。

   - 如果`i`不等于`j`,那么`dp[i][j]`就等于`f(i+1, j) + (m-j+i) * a[row][i]`和`f(i, j-1) + (m-j+i) * a[row][j]`中的较大值。这是因为,我们可以选择取第i个元素或者第j个元素,所以我们需要比较这两种选择的得分,取较大的那个。

4. 对于每一行,`f(0, m-1)`就是这一行的最大得分。程序将所有行的最大得分累加起来,就得到了总的最大得分。

这个程序的时间复杂度是O(n*m^2),因为它需要对每一行遍历所有可能的子数组。如果矩阵的大小非常大,那么这个程序可能会运行得比较慢。

注意,这个程序假设输入的矩阵的行数和列数不超过80,如果实际问题中矩阵的行数或列数可能超过这个值,那么需要相应地调整数组的大小。文章来源地址https://www.toymoban.com/news/detail-759837.html

代码实现2
#include <iostream>
#include <cstring>
using namespace std;

int dp[85][85];
int a[85][85];
int n,m,row;

int f(int i,int j){
    if(dp[i][j]){
        return dp[i][j];
    }
    if(i==j){
        return dp[i][j]=a[row][i]*m;
    }
    else{
        return dp[i][j]=max(f(i+1,j)+(m-j+i)*a[row][i],f(i,j-1)+(m-j+i)*a[row][j]);
    }
}

int main() {
    cin>>n>>m;
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
            cin>>a[i][j];
        }
    for(row=0;row<n;row++){
        memset(dp,0,sizeof(dp));
        ans+=f(0,m-1);
    }
    cout<<ans<<endl;
	return 0;
}

到了这里,关于[动态规划]矩阵取数游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划——地下城游戏

    leetcode在线oj题——地下城游戏 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的

    2024年02月11日
    浏览(38)
  • 动态规划之 跳跃游戏

    题目:力扣55 https://leetcode.cn/problems/jump-game/description/ 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1: 输入:nums = [

    2024年02月05日
    浏览(27)
  • 动态规划:跳跃游戏

    一)跳跃游戏: 55. 跳跃游戏 - 力扣(LeetCode) 一)定义一个状态表示: dp[i]表示以i未知元素为起点,是否能够到达最后一个位置 二)根据状态表示推到状态转移方程:根据最近的一步来进行划分问题 我们可以从当前i位置向后走j步,看看从i+j的位置是否能够到达最后一个位置, 那

    2024年02月16日
    浏览(28)
  • 力扣55. 跳跃游戏(动态规划)

    Problem: 55. 跳跃游戏 我们将问题稍做转换 每次求取当前位置可以走到的最远位置 ,在此基础上我们将最终判断是否能走出整个nums;同时我们要判断 中途会不会遇到某个位置是0使得不能继续走下去 时间复杂度: O ( n ) O(n) O ( n ) ;其中 n n n 为数组nums的大小 空间复杂度: O ( 1

    2024年02月21日
    浏览(30)
  • 动态规划之地下城游戏

    题目链接选自力扣 : 地下城游戏 一开始看到这么多文字, 头都大了. 下面就来根据示例的图帮助理解一下 骑士每次只能向右或者向下走一步 , 我们可以倒推一下示例的路线, 很容易就可以知道 按照我们往常的经验, 肯定是以 ( i, j ) 位置为结尾, 表示从起点到 ( i, j ) 位置时的所

    2024年02月11日
    浏览(17)
  • 【学会动态规划】地下城游戏(10)

    目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 学习一个算法没有捷径,更何况是学习动态规划, 跟我一起刷动态规划算法题,一起学会动态规划! 题目链接:174. 地下城游戏 - 力扣(Lee

    2024年02月14日
    浏览(27)
  • 动态规划--矩阵链相乘问题

    明确原始问题A[1:n]: 计算矩阵链 所需的 最小乘法次数。 (1)是否满足最优子结构,问题的解是否包含子问题的优化解? 若计算A[1:n]的优化顺序在 k 处断开矩阵链,即A[1:n]=A[1:k]×A[k+1:n],则在A[1:n]的优化顺序中,对应于子问题A[1:k]的解必须是A[1:k]的优化解,对应A[k+1:n]的解必

    2024年01月25日
    浏览(33)
  • 『动态规划』矩阵连乘

    活动地址:CSDN21天学习挑战赛 👨‍🎓作者简介:一位喜欢写作,计科专业大三菜鸟 🏡个人主页:starry陆离 🕒首发日期:2022年8月16日星期二 🌌上期文章:『动态规划』动态规划概述 📚订阅专栏:『算法分析与设计』 如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

    2024年02月07日
    浏览(55)
  • 矩阵链相乘(动态规划法)

    矩阵链乘法是耳熟能详的问题了,有很多矩阵,排列成矩阵链,矩阵链的要求是相邻的两个是可以相乘的,可以相乘是有条件的,两个矩阵能够相乘的条件就是行、列之间是有关系的,两个矩阵如果能够相乘,就是前面矩阵的列号和后面矩阵的行号是一致的。 如何确定矩阵的

    2024年02月09日
    浏览(35)
  • 【动态规划】矩阵连乘问题

    代码如下: 矩阵相乘,只有结合律没有交换律 。 显而易见,三个矩阵相乘,有两种结合方式,(AB)C 比 A(BC)的值小的多。 因此我们把它们进行划分,假设从第k个矩阵开始划分。如下图:就有 j个矩阵连乘的积 = R(第 i 个到第k矩阵的积 ) + U(第k+1到最后一个矩阵的积) + R*U 。

    2024年02月06日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包