2023年蓝桥杯省赛——蜗牛

news2024/11/26 16:57:57

目录

题目链接:1.蜗牛 - 蓝桥云课 (lanqiao.cn)

思路

暴力贪心

代码实不了现 

动态规划

代码实现

难点解释

总结


题目链接:1.蜗牛 - 蓝桥云课 (lanqiao.cn)

思路

暴力贪心

        蓝桥杯反正是能暴力出来一个用例是一个,我真的被折磨了好久,自以为自己的代码已经天衣无缝了,但是其实还是有一个致命的错误。那就是我这里采用的是贪心算法的思路,而没有采用动态规划的思路,我来说说为什么这里使用贪心算法的话会出现问题。

        我这里的代码思路就是每一个竹竿都判断到底是走下面直接走过来时间短还是使用传送门的时间短,这贪心的写法有一个致命的缺陷就是,如果我是采用的传送门来到的当前竹竿(传过来时传送门就在y=0的地方),然后这个传送到了这个竹竿的比如y=10^{100000000}的地方,正好这个竹竿传送到下一个竹竿的传送门在y=0的地方,然后如果我使用走到下一个竹竿只需要1米,那么我采用传送门是不是要先走完y=10^{100000000}再走一米,谁更快,这就是问题。

        代码如下(能过5%的用例,拿分就行):

代码实不了现 


import java.util.Scanner;

// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		// 接收参数
		// 正整数n,也是竹竿数组的长度
		int n = scanner.nextInt();
		// 竹竿位置存入数组,这里是按着索引挨个排列的
		int[] zgArr = new int[n];
		for (int i = 0; i < n; i++) {
			zgArr[i] = scanner.nextInt();
		}
		// 存入传送门的位置,n-1也是传送门数组的长度
		int[] csArrStart = new int[n - 1];
		int[] csArrEnd = new int[n - 1];
		for (int i = 0; i < n - 1; i++) {
			// 记录传送门在竹竿上的高度
			// 记录起始位置
			csArrStart[i] = scanner.nextInt();
			// 记录传送到的位置
			csArrEnd[i] = scanner.nextInt();
			
		}
		// 数据已经全部收到了,准备进入代码
		// 总体时间的花费
		// 这里初始化到第一根竹竿要花费一点时间
		double allTime = zgArr[0];
		
		// 记录一下当前的位置
		int nowX = zgArr[0];
		int nowY = 0;
		
		for (int i = 0; i < n - 1; i++) {
			
			if (i == n - 2) {
				// 直接走过去花费的时间
				double time1 = nowY / 1.3 + zgArr[i + 1] - nowX;
				
				//使用传送门花费的时间
				double time2 = 0;
				
				// a1 记录当前竹竿传送门的高度
				int a1 = csArrStart[i];
				
				if (nowY == a1) {
					// 已经在传送门的位置
					time2 += 0;
				}else if (nowY > a1) {
					// 在传送门的上面,往下走v=1.3
					time2 += (nowY - a1)/1.3;
				}else {
					// 在传送门的下面,往上走v=0.7
					time2 += (a1 - nowY)/0.7;
				}
				
				// 加上从传送门上下来到 y=0 位置花费的时间
				time2 += csArrEnd[i] / 1.3;
				
				allTime += Math.min(time1,time2);
				
				break;
			}
			
			// 竹竿之间的距离
			int dis = zgArr[i + 1] - nowX;
			// 如果直接走过去花费时间为
			double time1 = 0;
			if (nowY == 0) {
				time1 = dis;
			}else {
				// 说明现在在竹竿上,我们要先下去,然后再走过去
				time1 = nowY / 1.3 + dis;
			}

			//如果使用传送门
			double time2 = 0;
			// 要先走到传送门的位置
			// 获取该竹竿的传送门和下一个竹竿的传送到的高度
			int a1 = csArrStart[i];
			int b1 = csArrEnd[i];
			
			if (nowY == a1) {
				// 已经在传送门的位置
				time2 = 0;
			}else if (nowY > a1) {
				// 在传送门的上面,往下走v=1.3
				time2 = (nowY - a1)/1.3;
			}else {
				// 在传送门的下面,往上走v=0.7
				time2 = (a1 - nowY)/0.7;
			}
			if (time1 < time2) {
				// 直接走更快
				allTime += time1;
				// 更新坐标
				nowX = zgArr[i + 1];
				nowY = 0;
			}else {
				// 传送更快
				allTime += time2;
				nowX = zgArr[i + 1];
				nowY = b1;
			}
		}
		scanner.close();
		System.out.printf("%.2f", allTime);
	}
}


动态规划

        前面也是说了为什么我使用的贪心算法导致了问题的出错,这时候就只能使用动态规划来解决这个问题了。

        首先,我们创建了动态规划数组dp,数组的大小为n+1,其中每个元素dp[i]是一个包含两个元素的数组。dp[i][0]表示到达第i个竹竿底部的最短时间dp[i][1]表示到达第i个竹竿的传送门位置的最短时间。

        当然了,我们需要先初始化一下数据,也就是dp[1][0] = x[1]和dp[1][1] = x[1] + a[1] / 0.7;

        我们每次需要找到最短到达第i个竹竿底部的时间和最短到达第i个竹竿上的传送门的时间。

说的详细一点是:我们要找到从dp[i - 1][0] 和 dp[i - 1][1] 中的最短时间再加上路程来到当前竹竿的传送点,以及找到从dp[i - 1][0] 和 dp[i - 1][1] 中的最短时间再加上路程来到当前竹竿的底部。

        我们可以得到如下公式:

对于dp[i][1] :

a_{i}\geq b_{i}

dp[i][1] = min(dp[i - 1][0] + x[i] - x[i - 1] + \frac{a[i]}{0.7},dp[i - 1][1] + \frac{a[i] - b[i]}{0.7}))

a_{i}\leq b_{i} 

dp[i][1] = min(dp[i - 1][0] + x[i] - x[i - 1] + \frac{a[i]}{0.7},dp[i - 1][1] + \frac{b[i] - a[i]}{1.3})) 

对于dp[i][0] :

dp[i][0] = min(dp[i - 1][0] + x[i] - x[i - 1] ,dp[i - 1][1] + \frac{b[i]}{1.3}))

        这样子就成功的记录了每一种的情况,就不会有我们使用谈心算法的情况而导致的我们的路径其实并不是最短的路径了。

代码实现



import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 输入整数n,这个是竹竿的数量
        int n = sc.nextInt();
        // 存储竹竿的x坐标
        int[] x = new int[n + 1];
        // 存储 ai
        int[] a = new int[n + 1];
        // 存储 bi
        int[] b = new int[n + 1];
        // 将坐标数据存储进数组
        for (int i = 1; i <= n; i++) {
            x[i] = sc.nextInt();
        }
        // 将传送门的位置数据存入数组
        for (int i = 1; i < n; i++) {
            a[i] = sc.nextInt();
            b[i + 1] = sc.nextInt();
        }
        // 设置dp数组
        double[][] dp = new double[n + 1][2];
        // 初始化到第一个竹竿底部的时间
        dp[1][0] = x[1];
        // 初始化直接到第一个竹竿的传送门的时间
        dp[1][1] = x[1] + a[1] / 0.7;

        // 进入动态规划核心代码
        for (int i = 2; i <= n; i++) {
            // 先计算到竹竿传送门的时间
            if (a[i] > b[i]) {
                dp[i][1] = Math.min(dp[i - 1][0] + x[i] - x[i - 1] + a[i] / 0.7, dp[i - 1][1] + (a[i] - b[i]) / 0.7);
            } else {
                dp[i][1] = Math.min(dp[i - 1][0] + x[i] - x[i - 1] + a[i] / 0.7, dp[i - 1][1] + (b[i] - a[i]) / 1.3);
            }
            // 再计算到竹竿底部的时间
            dp[i][0] = Math.min(dp[i - 1][1] + b[i] / 1.3, dp[i - 1][0] + x[i] - x[i - 1]);
        }

        System.out.printf("%.2f", dp[n][0]);
        sc.close();
    }
}

 动态规划解决问题,你就说嗨皮不嗨皮就完事啦!!!

难点解释

        动态规划的主体部分,对第2个到第n个竹竿进行操作。这个for循环主要解决的问题是,每到一个新的竹竿,有两种可能的状态:一个是在竹竿上,不需要使用传送门;另一个是在传送门上。对于每种状态,有多种可能的情况,所以我们需要计算每种情况的时间,然后选择时间最短的那种。

        现在让我们看一下这段代码的具体操作:

dp[i][0] = Math.min(dp[i-1][1] +b[i]/1.3 ,dp[i-1][0]+x[i]-x[i-1]);

        这行代码表示,现在你已经到达了第i个竹竿,你可以选择从上一个竹竿直接爬过来,耗费的时间就是dp[i-1][0](上一个竹竿的时间)+ x[i]-x[i-1](爬过来的时间)。你还可以选择从传送门过来,耗费的时间就是dp[i-1][1](上一个传送门的时间)+ b[i] / 1.3(传送门下来耗费的时间)。然后比较这两种方式,选择一种时间较短的,存入dp[i][0]。

if(a[i]>b[i]){
    dp[i][1] = Math.min(dp[i-1][0] + x[i]-x[i-1] + a[i]/0.7, dp[i-1][1] + (a[i]-b[i])/0.7);
}else {
    dp[i][1] = Math.min(dp[i-1][0] + x[i]-x[i-1] + a[i]/0.7,dp[i-1][1] + (b[i]-a[i]) /1.3);
}

        对于dp[i][1],同样有两种情况。以第一种情况为例,在a[i] > b[i]时,你可以选择从上一个竹竿爬到传送门,然后通过传送门到达当前的竹竿,耗费的时间是dp[i-1][0] + x[i]-x[i-1] + a[i] / 0.7。也可以选择先从上一个传送门爬过来,然后走到当前竹竿的传送门,耗费的时间是dp[i-1][1] + (a[i]-b[i]) / 0.7。比较这两种方式,选择一种时间较短的,存入dp[i][1]。

总结

动态规划我学不了一点点,马上又要崩溃了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10.python的字典dict(上)

10.python的字典dict(上) 什么是字典 在计算机科学中&#xff0c;字典是一种数据结构&#xff0c;用于存储键值对&#xff08;key-value pair&#xff09;的集合。每个键值对都由一个唯一的键和一个对应的值组成。字典能够快速地根据键找到对应的值&#xff0c;因此在很多编程…

探索----------------阿里云

目录 一、阿里云四大件 1、云服务器ECS 2、云数据库RDS 3、负载均衡SLB 4、对象存储OSS 5、其他的云计算产品 1&#xff09;内容分发网络CDN 2&#xff09;专有网络 VPC 二、linux发行版本 三、你平时对系统会怎么优化&#xff08;五大负载&#xff09; 1、cpu 使用率…

有什么好用的网页在线客服系统?选择指南与实用推荐

有什么好用的网页在线客服系统&#xff1f; 企业与客户之间的互动变得越来越重要。为了提高客户满意度和提升企业形象&#xff0c;许多企业开始使用网页在线客服系统。网页在线客服系统是一种实时的、便捷的沟通工具&#xff0c;可以帮助企业与客户建立更紧密的联系。 一、网…

黑马点评项目笔记 II

基于Stream的消息队列 stream是一种数据类型&#xff0c;可以实现一个功能非常完善的消息队列 key&#xff1a;队列名称 nomkstream&#xff1a;如果队列不存在是否自动创建&#xff0c;默认创建 maxlen/minid&#xff1a;设置消息队列的最大消息数量 *|ID 唯一id&#xff1a;…

C++刷题篇——07检测热点字符

一、题目 二、解题思路 1、使用map&#xff0c;key为元素&#xff0c;value为出现的次数 2、由于sort不适用于map&#xff0c;因此要将map的key、value放到vector中&#xff0c;再对vector排序 3、对map排序&#xff1a;方法1&#xff1a;使用二维数组vector<vector<>…

蓝桥杯习题

https://www.lanqiao.cn/problems/1265/learning/ 第一题---排序 给定一个长度为N的数组A&#xff0c;请你先从小到大输出它的每个元素&#xff0c;再从大到小输出他的每个元素。 输入描述&#xff1a; 第一行包含一个整数N 第二行包含N个整数a1,a2,a3,...an&#xff0c;表…

解决多模块项目报错,找不到程序包

本周&#xff0c;我遇到了一个常见的错误——“找不到程序包”。这个错误是由于模块间的依赖关系没有正确配置导致的。经过一系列的尝试和排查&#xff0c;我最终找到了解决问题的方法。下面&#xff0c;我将详细记录这次问题的处理过程&#xff0c;并总结其中的经验教训。 问…

C/C++ 之 GSL 数学运算库使用笔记

Part.I Introduction 本文主要记录一下笔者使用 GSL 过程当中所做的一些笔记。 Chap.I 传送门 一些传送门 GSL源码&#xff08;CMakeList 版本-Windows&#xff09;GSL源码&#xff08;configure 版本-Linux&#xff09;GSL 在线文档GSL 文档下载 Chap.II GSL 简介 GSL 全…

使用通用内部函数对代码进行矢量化

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV 如何使用 XML 和 YAML 文件的文件输入和输出 下一篇&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; ​ 目标 本教程的目标是提供使用通用内…

网络基础(二)——序列化与反序列化

目录 1、应用层 2、再谈“协议” 3、网络版计算器 Socket.hpp TcpServer.hpp ServerCal.hpp ServerCal.cc Protocol.hpp ClientCal.cc Log.hpp Makefile 1、应用层 我们程序员写的一个个解决我们实际问题&#xff0c;满足我们日常需求的网络程序&#xff0c;都是在…

书生·浦语2.0(InternLM2)大模型实战--Day01 趣味 Demo | 部署InternLM2-Chat-1.8B模型

课程介绍 了解完书生浦语InternLM2大模型实战–基本认知 后&#xff0c;就可以做 Homework-demo 啦 Day01的作业基本是按照GitHub链接完成 GitHub – 轻松玩转书生浦语大模型趣味 Demo 作业截图如下 基本作业是实战第一部分 进阶作业的后两个是实战的的第三、四部分 我把进阶…

【STM32 HAL库SPI/QSPI协议学习,基于外部Flash读取】

1、SPI协议 简介 SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface)&#xff0c;即串行外围设备接口&#xff0c;是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间&#xff0c;要求通讯速率较高的场合。 通信方式&#xff1a;同…

编程语言|C语言——C语言操作符的详细解释

这篇文章主要详细介绍了C语言的操作符&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧 一、基础 1.1 算数操作符 - * / % - * / 这些操作符是我们…

Head First Design Patterns -代理模式

什么是代理模式 代理模式为另一个对象提供替身或者占位符&#xff0c;以便控制客户对对象的访问&#xff0c;管理访问的方式有很多种。例如远程代理、虚拟代理、保护代理等。 远程代理&#xff1a;管理客户和远程对象之间的交互。 虚拟代理&#xff1a;控制访问实例化开销大的对…

Unity类银河恶魔城学习记录11-10 p112 Items drop源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili ItemObject_Trigger.cs using System.Collections; using System.Collecti…

金融衍生品市场

金融衍生品市场 衍生金融品的作用衍生金融工具远期合约期货合约期权 衍生金融品的作用 套期保值&#xff08;Hedging&#xff09; 组合多头头寸(long position)与空头头寸(short position)例&#xff1a;股票与股指期货 投机 衍生金融工具 远期合约 定义&#xff1a;在将来…

Java基础入门--面向对象课后题(1)

某公司正进行招聘工作&#xff0c;被招聘人员需要填写个人信息&#xff0c;编写“个人简历”的封装类Resume&#xff0c;并编写测试类进行实现。类图及输出效果如下。 类名&#xff1a;Resumename : String (private)sex : String (private)age : int (private)Resume( ) // 没…

记录实现水平垂直居中的5种方法

记录块级元素实现水平垂直居中的方法&#xff0c;效果如图。 <div class"parent"><div class"child">居中元素</div> </div><style> .parent {position: relative;width: 600px;height: 300px;background-color: #679389; …

【安全用电管理系统的应用如何保证用电安全】Acrel-6000安科瑞智慧安全用电解决方案

政策背景 国家部委 ※2017年5月3日国务院安委会召开电气火灾综合治理工作视频会议&#xff0c;决定在全国范围内组织开展为期3年的电气火灾综合治理工作。 公安部领导 ※公安部副部长李伟强调&#xff1a;向科技要战斗力&#xff0c;加快推进“智慧消防”建设不断提升火灾防控…

第四篇:3.3 无效流量(Invalid traffic) - IAB/MRC及《增强现实广告效果测量指南1.0》

翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之- 3.1 广告印象&#xff08;AD Impression&#xff09;第三篇广告效果测量定义和其他矩阵之- 3.2 可见性 &#xff08;Viewability&#xff09;第四篇广…