蓝桥杯备赛day02 -- 算法训练题 拿金币Java

目录

题目:

问题描述

输入格式

输出格式

解题过程

第一步 定义dp数组

第二步 确定 dp 数组递推公式

 第三步 dp数组的初始化

第四步 dp数组的遍历顺序

第五步 举例说明

 报错:内存超限

用dp数组去存储位置上的金币

dp数组从二维降为一维

 收获:


 

题目:

问题描述

  有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。

输入格式

  第一行输入一个正整数n。
  以下n行描述该方格。金币数保证是不超过1000的正整数。

输出格式

  最多能拿金币数量。

样例输入

3
1 3 3
2 2 2
3 1 2

样例输出

11

数据规模和约定

n<=1000


解题过程

这是一道很明显的动态规划问题,那就老规矩动态规划五部曲。

第一步 定义dp数组

采用二维数组dp[ i ][ j ],定义为到第i行第j列时,拿到的最大金币数。

因此在定义数组长度时,需要是(n+1)*(n+1)

(因为数组索引从0开始)

又采用gold[ i ][ j ]数组,存储位置上的金币。

第二步 确定 dp 数组递推公式

我们只能往右走或者往下走,那么到达第i行第j列的位置,只能是从[ i ][ j-1 ]的位置(往右走)或者[ i-1 ][ j ] 的位置(往下走),

那么到[ i ][ j ]拿的金币应该为[ i ][ j-1 ][ i-1 ][ j ] 两者拿金币的最大值 加上[ i ][ j ]位置上的金币。

dp[i][j] = (Math.max(dp[i-1][j], dp[i][j-1]) + gold[i][j]);

 第三步 dp数组的初始化

  • 显然,在起点时,dp[1][1] = gold[1][1]
  • 在第一行时,我们只能往右走,这时dp[ i ][ j ] = dp[ i ][ j-1 ] + gold[ i ][ j ]。                         (注意往右是对 j 的变换,因此是 j-1 )
  • 在第一列时,我们只能往下走,这时dp[ i ][ j ] = dp[ i-1 ][ j ] + gold[ i ][ j ]。                         (注意往下是对i的变换,因此是 i-1 )

第四步 dp数组的遍历顺序

从左上角走到右下角,显然是i++,j++。 

第五步 举例说明

没啥可举例的哈。

最终代码如下,

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[][] dp = new int [n+1][n+1];
        int[][] gold = new int [n+1][n+1];
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++ )
                gold[i][j] = scanner.nextInt();
        dp[1][1] = gold[1][1];
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == 1 && j == 1) dp[i][j] = gold[1][1];
                else if(i == 1) dp[i][j] = dp[i][j-1] + gold[i][j];
                else if(j == 1) dp[i][j] = dp[i-1][j] + gold[i][j];
                else dp[i][j] = (Math.max(dp[i-1][j], dp[i][j-1]) + gold[i][j]);
            }
        }
        System.out.println(dp[n][n]);
    }
}

 报错:内存超限

乐,最终报错了,内存超限。十个评测记录,到第八个走不出来了。


随即就开始想办法优化。

要么将两个数组合并成一个数组,也就是用一开始用dp数组去存储位置上的金币,

要么将dp数组从二维降为一维。

用dp数组去存储位置上的金币

实际上操作跟之前没有什么不同,而且也是可行的。

因为数组是从左到右,从上到下遍历的dp[ i ][ j ] 修改后,就不需要起存储该位置上的金币的作用了,也就是时间错开了一下,从而起到数组有两个作用而不冲突。

代码如下

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[][] dp = new int[n+1][n+1];
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++ )
                dp[i][j] = scanner.nextInt();//用dp数组去存储位置上的金币
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == 1 && j == 1) dp[i][j] = dp[i][j]; 
                else if(i == 1) dp[i][j] = dp[i][j-1] + dp[i][j];
                else if(j == 1) dp[i][j] = dp[i-1][j] + dp[i][j];
                else dp[i][j] = (Math.max(dp[i-1][j], dp[i][j-1]) + dp[i][j]);
            }
        }
        System.out.println(dp[n][n]);
    }
}

dp数组从二维降为一维

  • 关键在于一个理清时间的思维。
  • 初始化时,我们用dp数组去存储第一行各位置,能拿到的最大金币。
  • 在最后一个for循环中,实现了先搜索第i行中的最大金币数,在搜索第i+1行的效果。
    • 两种情况,当j==1时,dp[j] += gold[i][j],意味着上一行中的dp[j],加上位置上的金币数,等于这一行第j列拿到的最大金币数。
    • 否则dp[j] = Math.max(dp[j-1],dp[j]) + gold[i][j]。其中max函数中的dp[j-1]意味着从左边来的,也就是左边位置的最大金币数,与从上边来(上一行)的最大金币数去最大值,加上位置上的金币数。
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[][] gold = new int[n+1][n+1];
        int[] dp = new int [n+1];
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                gold[i][j] = scanner.nextInt();
        //初始化
        for(int j = 1; j <= n; j++) {
            if(j == 1) dp[1] = gold[1][j];
            else dp[j] = dp[j-1] + gold[1][j];
        }
        for(int i = 2; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(j == 1) dp[j] += gold[i][j];
                else dp[j] = Math.max(dp[j-1],dp[j]) + gold[i][j];
            }
        }
        System.out.println(dp[n]);
    }
}

 第二个方法貌似有时候过不了第九个评测样例,然后多测几次就能通过了,不知道是官方系统的问题还是。

 收获:

for(int i = 1; i <= n; i++) 
    for(int j = 1; j <= n; j++ )
        num[i][j] = scanner.nextInt();

实现样例输入,看来java中隔一个空格后就会进行下一个变量的输入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/327368.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spark详解

Spark 概念 Spark 提供了一个全面、统一的框架用于管理各种有着不同性质&#xff08;文本数据、图表数据等&#xff09;的数据集和数据源&#xff08;批量数据或实时的流数据&#xff09;的大数据处理的需求。 核心架构 Spark Core 包含 Spark 的基本功能&#xff1b;尤其是…

计算机毕业设计 基于Java的国产动漫网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

A ConvNet for the 2020s

21世纪20年代的卷积神经网络 论文链接&#xff1a;https://arxiv.org/abs/2201.03545 项目链接&#xff1a;https://github.com/facebookresearch/ConvNeXt Abstract 视觉识别的“咆哮的20年代”始于视觉Transformer(ViT)的引入&#xff0c;它很快取代了卷积神经网络&#x…

Modbus协议

一.起源 Modbus由Modicon公司于1979年开发&#xff0c;是一种工业现场总线协议标准。Modbus通信协议具有多个变种&#xff0c;其中有支持串口&#xff0c;以太网多个版本&#xff0c;其中最著名的是Modbus RTU、Modbus ASCII和Modbus TCP三种。其中Modbus TCP是在施耐德收购Mo…

数据结构之树和二叉树

树和二叉树的定义和存储 二叉树的遍历 先序遍历 中序遍历 后序遍历 层次遍历 哈夫曼树

Packet Tracer - Layer 2 VLAN Security

Packet Tracer - 第二层VLAN安全配置任务 目标 在SW-1和SW-2之间建立新的冗余链路。在新连接的SW-1和SW-2之间的干线链路上启用中继并配置安全措施。创建一个新的管理VLAN&#xff08;VLAN 20&#xff09;并将一台管理PC连接到该VLAN。实施ACL以防止外部用户访问管理VLAN。 背…

Linux命令之服务器的网络配置hostname,sysctl,ifconfig,service,ifdown,ifup,route,ping的使用

1、查看当前主机名称&#xff0c;编辑配置文件修改主机名为你姓名拼音的首字母&#xff08;如张三&#xff0c;则为zs&#xff09; 2、查看本机网卡IP地址&#xff0c;编辑/etc/sysconfig/network-scripts/ifcfg-ens33&#xff0c;要求在一块物理网卡上绑定2个IP地址&#xff0…

测试阶段风险不容忽视!QA角色关键时刻揭露项目隐患!

项目有风险 今天下午15点&#xff0c;团队成员D向他的主管Z反馈他测试的项目有风险&#xff1a;项目在测试周期内&#xff0c;但在用例评审时发现有一处功能逻辑有争议&#xff0c;需要产品经理跟业务方确认&#xff0c;可能出现的情况有&#xff1a; 1.不变更需求&#xff0…

day2·算法-快乐数-有效三角形个数

今天又来更新啦&#xff0c;准备蓝桥杯的小伙伴可以和我一起来刷题&#xff0c;建议大家先看题&#xff0c;整理出思路&#xff0c;再看如何用简单的写法将思路构建出来&#xff0c;然后优化细节&#xff0c;找到解决某些例外出现的方法&#xff0c;从而成功解答这道题。 快乐…

leetcode 67. 二进制求和

一、题目 二、解答 1.思路 1.1 思路1 转成2个二进制数字相加&#xff0c;之后再转回字符串 1.2 思路2 遍历字符串挨个相加&#xff1a; 补齐2个字符串到同样长度 while循环&#xff0c;如果指针>0不断循环如果a短&#xff0c;给字符串前插入&#xff08;a长度-b长度&a…

万户 ezOFFICE ezflow_gd.jsp SQL注入漏洞复现

0x01 产品简介 万户OA ezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品,统一的基础管理平台,实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台,将外网信息维护、客户服务、互动交流和日…

Linux系统使用超详细(十)~vi/vim命令①

vi/vim命令有很多&#xff0c;其实只有少数的用法对于我们日常工作中起到了很大帮助&#xff0c;但是既然我选择梳理Linux的学习笔记&#xff0c;那么一定全力把自己的理解和学习笔记的内容认真整理汇总&#xff0c;内容或许有错误&#xff0c;还请发现的C友们发现了及时指出。…

day-11 统计整数数目

注&#xff1a;无思路 参考答案 code class Solution {static final int N 23;static final int M 401;static final int MOD 1000000007;int[][] d;String num;int min_sum;int max_sum;public int count(String num1, String num2, int min_sum, int max_sum) {d new in…

通过生成mcs、bin文件将程序固化到FPGA

通过将程序固化到FPGA&#xff0c;可以做到断电不丢失程序&#xff0c;上电之后就自动启动程序的作用&#xff0c;整个固化步骤主要分为3步&#xff0c;一是修改约束文件&#xff0c;二是生成mcs或bin文件&#xff0c;三是将程序固化到开发板flash 1.修改约束文件 生成固化文…

远程开发之vscode端口转发

远程开发之vscode端口转发 涉及的软件forwarded port 通过端口转发&#xff0c;实现在本地电脑上访问远程服务器上的内网的服务。 涉及的软件 vscode、ssh forwarded port 在ports界面中的port字段&#xff0c;填需要转发的IP:PORT&#xff0c;即可转发远程服务器中的内网端…

多行SQL转成单行SQL

如下图所示 将以上多行SQL转成单行SQL 正则表达式如下 (?s)$[^a-zA-Z()0-9]*结果如下 灵活使用,也未必只能使用Sublime Text 提供了一个在线工具

STM32快速复制MX25L1606E系列Flash

去年做了一个使用RS485对PIC18F45K80系列单片机进行在线升级的程序&#xff0c;如果是小批量的出厂烧录程序和升级验证&#xff08;出厂前肯定要测试单片机是否能正常读写Flash&#xff09;是可以的&#xff0c;但是后来产品订单量很大&#xff0c;生产线的烧录及升级验证就很缓…

【C语言基础考研向】03混合运算和printf讲解

一.混合运算 类型强制转换场景 整型数进行除法运算时&#xff0c;如果运算结果为小数&#xff0c;那么存储浮点数时一定要进行强制类型转换&#xff0c;请看下面例子 #include <stdio.h> int main() {int i5;float fi/2; //这里做的整型运算printf("%f\n",f…

BIOS知识枝桠——RAID 磁盘阵列

文章目录 前言一、RAID介绍二、RAID等级分类1.RAID02.RAID13.RAID24.RAID3和RAID45.RAID5和RAID66.RAID77.RAID10 BIOS下组建RAID 前言 假设存在多块磁盘&#xff0c;如果不组建阵列&#xff0c;磁盘与磁盘之间是没有任何关系的。磁盘A和B&#xff0c;放在A中的文件与B磁盘没有…

布隆过滤器四种实现(Java,Guava,hutool,Redisson)

1.背景 为预防大量黑客故意发起非法的时间查询请求&#xff0c;造成缓存击穿&#xff0c;建议采用布隆过滤器的方法解决。布隆过滤器通过一个很长的二进制向量和一系列随机映射函数&#xff08;哈希函数&#xff09;来记录与识别某个数据是否在一个集合中。如果数据不在集合中…