当青训营遇上码上掘金
问题
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路
- 移动对象:只有小青。
- 移动方向:由于两人距离在一条直线,则只考虑前后移动。那么移动方向即为小青->小码。
- 移动方式:当K<N,只能选择步行;当K>N且满足条件0<=N,那么公交在相同时间内到达的距离最远,应该优先选择公交,若满足K=2Nn+1,那么移动方式则为n分钟公交与1分钟的步行。
解决方式
本题为求两点之间的最短路径,常见的方法是Dijkstra算法(贪心算法的策略),Bellman-Ford算法,SPFA算法(Bellman-Ford算法的队列优化算法的别称),Floyd算法(动态规划思想)。
那么本次采用动态规划方式来进行问题解决:先分析最优子结构,找到最佳子问题。用dp数组存储每个子问题的解,i为当前位置,n和k分别为两人的家的位置。当移动方向为正方向时,对距离的奇偶进行分类构建状态方程dp[i] = min(dp[(i + 1) / 2] + 2, dp[i - 1] + 1);如果为负方向,则直接设最短时间为n-k。
代码采用C++:
using namespace std;
int N=10000;
int dp[15000];
int main() {
int n = 0, k = 0, ans1 = 0;
cin >> n >> k;
if (n >= k) ans1 = n - k; //如果是负坐标,则选择步行
else { //反之,优先选择公交
for (int i = 0; i <= n; i++) {
dp[i] = n - i;
}
//构建状态转移方程
for (int i = n + 1; i <= k; i++) {
if ((i % 2 = 0)) {
dp[i] = dp[i / 2] + 1; //若距离为偶数
}
else {
dp[i] = min(dp[(i + 1) / 2] + 2, dp[i - 1] + 1); //若距离为奇数
}
}
ans1 = dp[k];
}
cout << ans1;
return 0;
}
总结
寻友之旅其实类似于我们求最短路径,不过该题难度较小一些,只有两个确定点,我们可以直接选择动态规划的方法,求解最短时间其原理是重叠子问题和最优子结构,经典模型则有线性模型、区间模型和背包模型,符合本次实验。如果遇到明显的多节点求最短路径,也可以考虑四大算法进行求解,主要是留意各个算法之间的区别。