当青训营遇上码上掘金
一、题目概述
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
二、思路分析
2.1 题目分析
本题的输入参数:
- 小青的地点 N(整型,范围是 )
- 小码的地点 K(整型,范围是 )
输出结果:小青到小码家的最短时间(以分钟为单位,即为整型,结果范围应当 )
2.2 情况分析
1
即小青的位置坐标比小码大。根据题目,公交车不可以往后走。这种情况下,只能通过步行方式前往。所花费的时间即为 。
2
小青与小码的位置坐标重合。这种情况下小青不需要任何方式前往,所花费的时间为 。
3
这种情况下有多种方式可以使用。
直接步行
结果为 。但是分析可知。这种情况几乎不可能是最优。即便是最优,也会被以下几种方式覆盖。
乘公交车前往离小码位置最近的点然后步行
乘公交车坐过一站后步行返回
乘公交车到离小码坐标一半最近的点并步行至此再坐公交
2.3 细节分析
- 若小青位置为0,乘坐公交只能原地踏步,因此必须至少先步行到1再乘坐公交
- 若乘坐公交的位置大于50000,再乘坐公交会大于最大坐标。因此认为此时乘坐公交一分钟可到达最大坐标位置
- 题目中数据处理均为整数,因此不存在到达小数位置坐标的情况
- 若输入不合法应当提示错误信息
三、代码详解
本题采用 Java 完成。
3.1 数据输入
Scanner in = new Scanner(System.in);
System.out.println("请输入小青地点 N:");
int N = in.nextInt();
if( N<0 || N>LIMIT ) {
System.out.println("小青地点输入有误");
return;
}
System.out.println("请输入小码地点K");
int K = in.nextInt();
if( K<0 || K>LIMIT ) {
System.out.println("小码地点输入有误");
return;
}
新建一个 Scanner 对象用于数据的输入。对于输入小青和小码的坐标进行判断,如果不是在题目给定的范围内,提示错误并结束程序。
3.2 的简单情况
if( N==K ) { // 两人在同一点
System.out.println("0 min!已经到啦!");
} else if( N>K ) { // 只能步行
System.out.println("还要 " + (N-K) + " min! 走过来啦!");
}
这种情况下要么步行到达要么直接坐标点重合,情况简单。
3.3 分别计算几种方案的时间
首先处理特殊情况:小青坐标点为0。这个时候先步行至坐标点 1,再进行处理。
if( N==0 ) { // 起点在 0 不能坐公交
N = N + 1;
temp = temp + 1;
T0 += 1;
t0 += 1;
}
“跨越”相同的距离,乘坐公交比步行更快。因此先乘坐公交到离小码坐标点最近的“小点”(坐标值比小码小)。
while( 2*N<K ) { // 公交快速接近
t0 += 1;
N *= 2;
}
直接走路,所花费的时间即两点的距离。
// 方案一 直接走路
int t1 = K - N + t0;
走到小码坐标点一半的位置,再乘坐公交前往。
// 方案二 后退至可乘坐公交
int t2;
if( K%2==0 ) { // 地点 K 恰好能坐公交到
t2 = N - K/2 + 1;
} else {
t2 = N + 1 - (K+1)/2 + 1;
}
t2 += t0;
多坐一站公交,走路返回小码的位置。
// 方案三 坐过站返回
int t3;
t3 = (2*N < LIMIT ? 2*N : LIMIT ) - K + t0 + 1;
先移动到小码坐标点一半的位置再坐公交。
int t4;
while( temp*2<K/2 ) {
T0 += 1;
temp *= 2;
}
int dis1, dis2;
if( K%2==0 ) {
dis1 = K/2 - temp;
dis2 = temp * 2 - K/2;
} else {
dis1 = (K-1)/2 - temp;
dis2 = 2*temp - (K+1)/2;
}
if( dis1 < dis2 ) {
t4 = T0 + Math.abs(dis1) + 1;
} else {
t4 = T0 + 1 + Math.abs(dis2)+ 1;
}
对这四种方案进行比较,取最小值并输出。
f( t1<=t2 && t1<=t3 && t1<=t4 ) {
System.out.println("还要 " + t1 +" min");
} else if( t2<=t1 && t2<=t3 && t2<=t4 ) {
System.out.println("还要 " + t2 +" min");
} else if( t3<=t1 && t3<=t2 && t3<=t4 ) {
System.out.println("还要 " + t3 +" min");
} else if( t4<=t1 && t4<=t2 && t4<=t3 ) {
System.out.println("还要 " + t4 +" min");
}
四、测试结果
4.1 一般情况
输入:N=500, K=200
输出:300
输入:N=450,K-450
输出:0
输入:N=200,K=500
输出:51
4.2 小青坐标点为0
输入:N=0,K=5000
输出:465
输入:N=0,K=100000
输出:18
五、反思总结
本题一开始在解决时忽略了一些边界条件,导致出错。 目前的版本几种方案仍然存在这重叠的情况,尚可进行优化。
源代码链接为:主题三源代码
欢迎大家批评指正!