作者主页:Designer 小郑
作者简介:Java全栈软件工程师一枚,来自浙江宁波,负责开发管理公司OA项目,专注软件前后端开发(Vue、SpringBoot和微信小程序)、系统定制、远程技术指导。CSDN学院、蓝桥云课认证讲师,全栈领域优质创作者,在校期间参加PAT乙级考试获得满分,三年ACM竞赛经验,斩获国奖两项,省奖五项。热爱技术、专注业务、开放合作、乐于分享,期待你我共同成长!
主打方向:Vue、SpringBoot、微信小程序
题目链接:题目链接
题面:
小王最近得到了一艘神奇的飞船,这艘飞船只有两个脚踏板,分别是油门和刹车,飞船的原始速度 N
。
假设飞船的现有速度为 X
,每当小王踩一下油门后,就会加速到 X * X
。
假设飞船的现有速度为 Y
,每当小王踩一下刹车后,飞船速度就会减速到 Y - 1
。
这并不神奇,神奇的是飞船会出一道题,如果飞船驾驶员能正确解答这道题,就可以召唤出一条神龙,实现驾驶者的一个愿望。飞船出题的内容是求出踩脚踏板后达到预定的速度 M
(0 < M < 400000)的最少次数。
小王特别想有一个女朋友陪他一起遨游太空,你能帮助小王解决这个问题让他召唤出神龙满足有女朋友的愿望吗?
本次挑战需要你至少了解一些 Java 中诸如流程控制、数组、集合或队列的使用。
知识点
- 队列/背包的基本使用
- 广度优先搜索
- 最佳解决方案
初始代码
import java.util.*;
public class SpaceShip{
public static int fly(int N,int M){
int ans = 0;
//代码编辑区 开始
//代码编辑区 结束
return ans;
}
public static void main(String[] args) {
//测试用例
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为3次.\n",2,15,fly(2, 15));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为5次.\n",5,21,fly(5, 21));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为13次.\n",5,30,fly(5, 30));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为26次.\n",5,125,fly(5, 125));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为78次.\n",5,173010,fly(5, 173010));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为752次.\n",11,200000,fly(11, 200000));
System.out.printf("从%d 到 %d 最少需要踩:%d 次,正确答案为2次.\n",52,50,fly(52, 50));
}
}
样例说明
输入初始速度 N 和目标速度 M,输出踩脚踏板的最小次数。
如初始速度 N = 2,目标速度为 15,只需依次踩油门、油门、刹车即可达到,最少只需要踩 3 次。
如初始速度 N = 52,目标速度为 50,只需依次踩刹车、刹车即可达到,最少只需要踩 2 次。
刹车与油门可以只踩一种或交替进行踩踏。
题解
考察 Java 队列和 bfs 的使用,当然也可以用动态规划的思想去解决问题,对于初始速度 N
和目标速度 M
,需要考虑到下列三种情况。
1 初始速度 N
>= 目标速度 M
,答案为 N - M
,因为小王只能通过踩刹车减速。
2 初始速度 N
< 目标速度 M
,小王可以通过踩油门或刹车控制速度,使用广搜思想分类讨论,最终得出答案。
参考代码如下:
import java.util.*;
public class SpaceShipAns{
// 请勿修改 fly() 的方法名和参数类型
public static int fly(int n,int m){
int ans = 0;
//代码编辑区 开始
if(n >= m) {
return n - m;
}
init();
integerList.set(n,0);
q.add(new NodeVo(0,n));
while(q.size() > 0) {
NodeVo vo = q.peek();
q.poll();
if(integerList.get(vo.getId()) < vo.getT()) {
continue;
}
if(vo.getId() <= 632) {
int index = vo.getId() * vo.getId();
int t = vo.getT() + 1;
if(integerList.get(index) > t) {
integerList.set(index,t);
q.add(new NodeVo(t,index));
}
}
if(vo.getId() > 2) {
int index = vo.getId() - 1;
int t = vo.getT() + 1;
if(integerList.get(index) > t) {
integerList.set(index,t);
q.add(new NodeVo(t,index));
}
}
}
ans = integerList.get(m);
//代码编辑区 结束
return ans;
}
public static void main(String[] args) {
//测试用例
System.out.printf((Objects.equals(3,fly(2, 15)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 3 次\n",2,15,fly(2, 15));
System.out.printf((Objects.equals(5,fly(5, 21)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 2 次\n",5,21,fly(5, 21));
System.out.printf((Objects.equals(13,fly(5, 30)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 13 次\n",5,30,fly(5, 30));
System.out.printf((Objects.equals(26,fly(5, 125)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 26 次\n",5,125,fly(5, 125));
System.out.printf((Objects.equals(78,fly(5, 173010)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 78 次\n",5,173010,fly(5, 173010));
System.out.printf((Objects.equals(752,fly(11, 200000)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 752 次\n",11,200000,fly(11, 200000));
System.out.printf((Objects.equals(2,fly(52, 50)) ? "【√正确】" : "【X错误】") + "从%d 到 %d 最少需要踩:%d 次,正确答案为 2 次\n",52,50,fly(52, 50));
}
private static List<Integer> integerList;
private static Queue<NodeVo> q;
private static class NodeVo implements Comparable<NodeVo>{
private int t;
private int id;
public NodeVo(int t,int id) {
this.t = t;
this.id = id;
}
public int getT() {
return t;
}
public void setT(int t) {
this.t = t;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public int compareTo(NodeVo other) {
return t > other.t ? 1 : 0;
}
}
private static void init() {
integerList = new ArrayList<>();
for(int i = 0;i < 500000; i ++) {
integerList.add(999999999);
}
q = new LinkedList<>();
}
}
总结
要 AC 本题,必须学会基于队列的 BFS (即广度优先搜索)的算法,从而通过本题。