[华为OD]BFS C卷 200 智能驾驶

题目:

有一辆汽车需要从m*n的地图的左上角(起点)开往地图的右下角(终点),去往每一个地区都需 

要消耗一定的油量,加油站可进行加油

请你计算汽车确保从起点到达终点时所需的最少初始油量说明:

(1)智能汽车可以上下左右四个方向移动1

⑵地图上的数字取值是0或-1或者正整数:

-1:表示加油站,可以加满油,汽车的油箱容量最大为100;

0:表示这个地区是障碍物,汽车不能通过

正整数:表示汽车走过这个地区的耗油量

⑶如果汽车无论如何都无法到达终点,则返回-1

输入描述

第一行为两个数字,M, V,表示地图的大小为M,N(0< M,N < 200)

后面一个M*N的矩阵,其中的值是0或-1或正整数,加油站的总数不超过200个

输出描述

如果汽车无论如何都无法到达终点,则返回-1

如果汽车可以到达终点,则返回最少的初始油量

示例1 

输入

2,2 

10,20 

30,40

输出

70

示例2 

输入

4,4 

10,30,30,20 

30,30,-1,10 

0,20,20,40

10,-1,30,40 

输出

70

示例3

输入

4,5

10,0,30,-1,10 

30,0,20,0,20 

10,0,10,0,30 

10,-1,30,0,10 

输出

60

示例4

输入

4,4

10,30,30,20 

30,30,20,10 

10,20,10,40 

10,20,30,40 

输出

-1

题解:这个题目要计算最少初始油料,那么如果经过加油站的话,明显就要直接加满油。

比较明显的BFS题目。但是需要判断到加油站的情况。由于油箱容量100,那么我们出发时候就将当前油量设置为100。

依旧还是需要定义一个内部类,参数有x,y坐标。这个里面就加了,初始油量originalOil,当前坐标走完需要油量needOil,也就是矩阵中当前的值。以及汽车在这个坐标的剩余油量restOil,还有一个bool值,是否有在加油站加过油。

1)如果到加油站时候,车辆没有加过油,那么从出发到这个加油站的初始油量(刚出发时候初始油量)就可以变为100减去当前剩余油量了。

2)当BFS向下一坐标搜索的时候,如果restOil剩余油量不足以满足去下一个坐标需要的油量needOil,那么就继续往下搜索

3)在到终点的时候,如果没有加过油,那么如果剩余油量>0,那么这个路径走下来的初始油量应该可以变成100减去当前剩余油量

4)当走到任意坐标时候,油量足够,而且汽车加过油,那么初始油量应该不变,因为加过油,剩余油量在加油站那个坐标直接变为100了

5)走过一个坐标,那么这个坐标访问标记visit[x][y]=1;

这个里面可以看到有一个难点就是可能有两条路线能经过同一个加油站,两条路径油量不同,如何确保最终是最少油量经过这个加油站。这边采用的是一个map<String,Integer> oilStations来解决表示的是这个加油站坐标和来这个加油站最少得油量。因为在初始化扫描的时候当矩matrixs[i][j]==-1,就是加油站,那么此时就初始化这个加油站油量为Integer.MaxValue.

6)那么在经过加油站的坐标时候,加油站坐标的visit[x][y],还是为0,不能变为1,防止其他路径更少油量,由于visit[x][y]==1,而不能到加油站,结果就不对。此时,先根据oilStations,拿到抵达这个加油站当前的最少油量prsentLeastOil,如果这个路径到这个加油站的最少油量小于

prsentLeastOil,那么说明现在这个路径就更优,那么就把这个路径继续扫描下去,也就是将这个路径的点加入到队列中去。如果大于等于,这条路径就不用继续扫描了,明显不是最优解,不能为等于是因为防止两个加油站相邻,那么等于的话,明显路径会在这两个加油站一直循环扫。

7)用一个列表表示每个到终点的路径最少油量,最后排序取第一个值就是最少初始油量了

这个题感觉难度就在处理加油站的逻辑上面。

代码:

import java.util.*;

public class CarPath {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] matrix = sc.nextLine().split(",");
        int m = Integer.valueOf(matrix[0]);
        int n = Integer.valueOf(matrix[1]);
        int matrixs[][] = new int[m][n];
        int visit[][] = new int[m][n];
        Map<String, Integer> oilStations = new HashMap<>();
        for (int i = 0; i < m; i++) {
            String[] data = sc.nextLine().split(",");
            for (int j = 0; j < n; j++) {
                matrixs[i][j] = Integer.valueOf(data[j]);
                visit[i][j] = 0;
                if (matrixs[i][j] == -1) {
                    oilStations.put(String.valueOf(i) + String.valueOf(j), Integer.MAX_VALUE);
                }
            }
        }

        int startX = 0;
        int startY = 0;
        int endX = m - 1;
        int endY = n - 1;
        Path startPath = new Path(startX, startY, matrixs[0][0], 100 - matrixs[0][0]);
        startPath.originalOil = 100;
        visit[0][0] = 1;
        Queue<Path> queue = new LinkedList<>();
        queue.offer(startPath);

        List<Integer> needOil = new ArrayList<>();
        boolean hasRoote = false;

        int dirctions[][] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};

        // BFS
        while (!queue.isEmpty()) {
            Path frontPath = ((LinkedList<Path>) queue).getFirst();
            if (frontPath.x == endX && frontPath.y == endY) {
                hasRoote = true;
                ((LinkedList<Path>) queue).pollFirst();
                continue;
            }

            for (int i = 0; i < 4; i++) {
                int newX = frontPath.x + dirctions[i][0];
                int newY = frontPath.y + dirctions[i][1];

                if (newX >= 0 && newX < m && newY >= 0 && newY < n) {
                    System.out.println("newX " + newX + " newY " + newY);
                    if (newX == 3 && newY == 3) {
                        System.out.println("error0");
                    }
                    if (newX == endX && newY == endY) { // 下一个是终点
                        Path endPath = new Path(newX, endY, matrixs[newX][newX], frontPath.getRestOil() - matrixs[newX][newX]);
                        if (endPath.restOil < 0) { // 油不足以走到终点
                            continue;
                        } else {
                            if (frontPath.hasAddOil) { //加过油
                                endPath.originalOil = frontPath.originalOil;
                            } else {//全程没有加过油 并且有多的油
                                endPath.originalOil = frontPath.originalOil - endPath.restOil;
                            }
                            needOil.add(endPath.originalOil);
                            hasRoote = true;
                            queue.offer(endPath);
                            continue;
                        }
                    }

                    if (matrixs[newX][newY] != 0 && matrixs[newX][newY] != -1 && visit[newX][newY] == 0) { //下一个是一般道路
                        Path nextPath = new Path(newX, newY, matrixs[newX][newY],
                                frontPath.getRestOil() - matrixs[newX][newY]);
                        if (nextPath.restOil < 0) { // 油不足以走到终点
                            continue;
                        } else {
                            nextPath.hasAddOil = frontPath.hasAddOil;
                            if (frontPath.hasAddOil) {//加过油
                                nextPath.originalOil = frontPath.originalOil;
                            } else { //没加过油 需要的油就要加上当前道路需要的油
                                nextPath.originalOil = frontPath.originalOil;
                            }
                        }
                        if (nextPath.x == 3 && nextPath.y == 3) {
                            System.out.println("error");
                        }
                        queue.offer(nextPath);
                        visit[newX][newY] = 1;
                        continue;
                    }

                    if (matrixs[newX][newY] == 0) {
                        visit[newX][newY] = 1;
                        continue;
                    }
                    if (matrixs[newX][newY] == -1 && visit[newX][newY] == 0) { // 到加油站了,这个题明显到加油站都得加满油
                        Integer prsentLeastOil = oilStations.get(String.valueOf(newX) + String.valueOf(newY));
                        if (frontPath.restOil >= prsentLeastOil) {
                            continue;
                        }
                        oilStations.put(String.valueOf(newX) + String.valueOf(newY), frontPath.restOil);
                        Path nextPath = new Path(newX, newY, matrixs[newX][newY],
                                100);// 加油站直接加满油
                        nextPath.hasAddOil = true;
                        if (!frontPath.hasAddOil) {// 前面没有加过油
                            nextPath.originalOil = frontPath.originalOil - frontPath.restOil;// 需要的油应该是前车需要的油料减去前车剩余油料,因为初始化是100
                        } else { // 前面已经加过油
                            nextPath.originalOil = frontPath.originalOil;
                        }
                        visit[newX][newY] = 0;  //加油站不设置访问标记 通过判断到加油站剩余油料是最少得来判断是否将当前数据加入队列,继续扫描
                        if (nextPath.x == 3 && nextPath.y == 3) {
                            System.out.println("error1");
                        }
                        queue.offer(nextPath);
                        continue;
                    }
                }
            }

            ((LinkedList<Path>) queue).pollFirst(); //首元素推出队列
        }

        if (hasRoote) {
            Collections.sort(needOil);
            System.out.println(needOil.get(0));
        } else {
            System.out.println(-1);
        }


    }

    private static class Path {
        int x;
        int y;
        int needOil;
        int restOil;
        int originalOil;
        boolean hasAddOil;//是否加过油

        public Path(int x, int y, int needOil) {
            this.x = x;
            this.y = y;
            this.needOil = needOil;
        }

        public Path(int x, int y, int needOil, int restOil) {
            this.x = x;
            this.y = y;
            this.needOil = needOil;
            this.restOil = restOil;
        }


        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }

        public int getNeedOil() {
            return needOil;
        }

        public void setNeedOil(int needOil) {
            this.needOil = needOil;
        }

        public int getRestOil() {
            return restOil;
        }

        public void setRestOil(int restOil) {
            this.restOil = restOil;
        }

        public Path(int originalOil) {
            this.originalOil = originalOil;
        }

        public Path(boolean hasAddOil) {
            this.hasAddOil = hasAddOil;
        }
    }
}

验证:

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

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

相关文章

PyQt5中的QGraphicsView()

文章目录 1. 简介2. 一个简单的示例2. 加载一幅图片3. 常用方法示例 1. 简介 QGraphicsView是PyQt5中用于显示图形场景的小部件&#xff0c;它提供了许多常用的方法来控制视图的行为和属性。下面是一些常用的QGraphicsView方法&#xff1a; setScene(scene): 设置要显示的场景…

GCP谷歌云有什么数据库类型,该怎么选择

GCP谷歌云提供的数据库类型主要包括&#xff1a; 关系型数据库&#xff1a;这类数据库适用于结构化数据&#xff0c;通常用于数据结构不经常发生变化的场合。在GCP中&#xff0c;关系型数据库选项包括Cloud SQL和Cloud Spanner。Cloud SQL提供托管的MySQL、PostgreSQL和SQL Se…

Office之Word应用(二)

一、页眉添加文件名称和页码 1、双击页眉&#xff0c;点击“页眉-空白&#xff08;三栏&#xff09;” 2、删掉第一处&#xff08;鼠标放在上面就会选中&#xff0c;Enter即可&#xff09;&#xff0c;第二处输入文档名称&#xff0c;第三处插入页码。 注&#xff1a;插入页码时…

微信小程序毕业设计-基于Java后端的微信小程序源码150套(附源码+数据库+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享150的微信小程序毕业设计&#xff0c;后台用Java开发&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设…

灾备建设中虚拟机备份自定义数据块大小应用

灾备建设中&#xff0c;传输备份数据时&#xff0c;自定义数据块大小可以帮助优化数据传输和存储效率。 确定数据块大小&#xff0c;首先&#xff0c;需要确定合适的数据块大小。这可以根据备份数据量和网络带宽来决定。通常情况下&#xff0c;较小的数据块可以更好地适应网络…

82.网络游戏逆向分析与漏洞攻防-移动系统分析-坐标修正数据包的处理与模拟

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

采油厂职工向媒体投稿的好方法找到了

作为一名采油厂的职工,我深知在媒体上定期投稿的重要性。这不仅是我们展示工作成果、传播企业文化的重要途径,更是上级考核我们工作表现的一项指标。然而,在投稿的过程中,我经历了不少心酸与困扰。 起初,我采用传统的邮箱投稿方式。每天,我都会花费大量时间在网络上搜索合适的媒…

kafka 图形化

介绍 idea 中的一个插件 kafkalytic,kafka 图形化 简单又强大 安装 使用界面 总体信息 数据查看

Python管理PVE(Proxmox VE)云平台--节点资源统计

一、前言 写本脚本的初衷是因手动查看统计已分配的PVE资源过于耗时&#xff0c;因此写一个脚本一劳永逸&#xff0c;具体实现方法&#xff1a;利用Python的paramiko模块进行远程命令查看、统计PVE平台各节点已分配的cpu、内存、磁盘空间。 二、步骤 1.构建shell脚本 1.1 统计…

每日一题 城市群的数量

题目解析 城市群数量_牛客题霸_牛客网 当解决这个问题时&#xff0c;首先需要理解题目要求。题目中给出了一个城市之间的邻接矩阵&#xff0c;矩阵中的元素表示城市之间是否直接相连。如果两个城市直接相连&#xff0c;或者通过其他城市间接相连&#xff0c;它们就属于同一个城…

进程间的IPC通信机制

一、介绍 进程与进程间的用户空间相互独立&#xff0c;内核空间共享。 1.传统的进程间通信机制 a.无名管道 pipe b.有名管道 fifo c.信号 signal 2.system V中的IPC对象 a.消息队列 message queue b.共享内存 shared memory c.信号灯集 semaphoare 3.可用于跨主机传输…

Weblogic 任意文件上传漏洞(CVE-2018-2894)

1 漏洞描述 CVE-2018-2894漏洞存在于Oracle WebLogic Server的Web服务测试页面&#xff08;Web Service Test Page&#xff09;中。这个页面允许用户测试Web服务的功能&#xff0c;但在某些版本中&#xff0c;它包含了一个未经授权的文件上传功能。攻击者可以利用这个漏洞&…

变频器通过Modbus转Profinet网关接电机与PLC通讯在自动化的应用

Modbus转Profinet网关&#xff08;XD-MDPN100/300/600&#xff09;的作用是将Modbus协议转换为Profinet协议&#xff0c;支持Modbus RTU主站/从站&#xff0c;并且Modbus转Profinet网关设备自带网口和串口&#xff0c;既可以实现协议转换的同时&#xff0c;也可以实现接口的转换…

ARM架构安全特性之隔离技术

安全之安全(security)博客目录导读 目录 一、保护代码和数据 二、TrustZone 三、安全世界之间的隔离 四、Secure-EL2扩展 五、保护主流计算工作负载 六、领域管理扩展(RME) 七、内存密集型可信应用程序 八、Arm动态TrustZone技术 强制执行明确定义的安全边界是安全工程…

变现 5w+,一个被严重低估的 AI 蓝海赛道,居然用这个免费国产AI工具就能做!

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 文章首发于公众号&#xff1a;X小鹿AI副业 之前X小鹿一直在各…

HTML与cgi程序的数据交互

1. Html通过ajax获取cgi返回的数据 function HtmlGetCgiData() {$.ajax({type: POST, //提交方法url: cgi-bin/wg67_key_in/wg67_key_in_reflush.cgi, //调用到的cgi程序data: "ajax", //发送的数据&#xff0c;不可缺失该项&#xff0c;不能为空&#xff08;空&…

从“金事通”带给我意想不到的来说--“数据是架构的中心”

背景 上周一个保险的销售人员来找我完成一定的售后流程。其中有一项是请我下载一个叫 金事通的 APP。说实在的我根本没听过。她说这是政治任务。我想不是有你们保险公司的APP了嘛。为什么还要我安装。没办法先安装吧。 经历了注册、人脸识别的步骤后。可以登录了。注册短信发…

AR系列路由器配置本地同一网段互通

A R 路由器是华为公司推出的企业级路由器产品系列&#xff0c;具有高可靠性、高性能和易管理等特点。AR 系列路由器提供的功能包括路由转发、安全接入、语音、视频、无线等多种业务&#xff0c;支持各种接入方式和协议&#xff0c;并且可以方便地进行扩展和升级。 实验拓扑图&…

Spring:@Async注解使用注意事项及九大失效场景

前言 原文作者&#xff1a;微信公众号&#xff1a;苏三说技术 场景举例 代码案例 点击此处可观看&#xff1a;Async注解使用注意事项及九大失效场景

浪潮信息联合SAP助力玉柴集团实现数字化转型的飞跃

数字化时代下&#xff0c;企业面临着前所未有的机遇和挑战。为顺应这一趋势&#xff0c;众多企业纷纷踏上了数字化转型的征程&#xff0c;其中就包括玉柴集团。值得一提的是&#xff0c;在玉柴集团转型过程中&#xff0c;SAP、浪潮信息等国际一流厂商予以了强大的算力支持&…