青训营寻友之旅

65 阅读2分钟

当青训营遇上码上掘金

题目简介

寻友之旅

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

思路分析

经典的算法问题,作者本来打算使用动态规划来处理此题,但由于小青可以后退一格使得我们的递推公式无法得出,若只能前进不能后退,动态规划将是最好的解决方法。如今我们只能考虑暴力解决问题,但105的数据量我们需要一些技巧,这时搜索算法登场了。

广度优先搜索BFS

利用队列先进先出的特性,让起始位置进入队列,轮换的执行后退前进与翻倍操作。由于我们执行一轮操作时,消耗的步数都是相同的,所以所有的执行步骤等价,最先到达目的地的即为最优方案。那么问题就转换成了记录每一步的位置与步数,有序的执行后退前进和翻倍操作。

C++实现如下

#include <iostream>
#include <queue>

using namespace std;

typedef pair<int, int> PII;
queue<PII> q;

int main()
{
  int n, k;
  cin >> n >> k;
  q.push({n, 0});
  int res = 0;	
  while(q.size())
  {
  	PII t = q.front();
  	q.pop();
  	if(t.first < 0)
  		continue;
  	else if(t.first == k)
  	{
  		res = t.second;
  		break;
  	}
  	for(int i = 0; i < 3; i++) 
  	{
  		switch(i)
  		{
  			case 1: q.push({t.first-1, t.second+1}); break;
  			case 2: q.push({t.first+1, t.second+1}); break;
  			default: q.push({t.first*2, t.second+1});
  		}
  	}
  }
  cout << res;
  return 0;
}

在此时,我们使用res接收最优结果,静静等待即可。

总结

计算机最擅长计算,而编码的目的是为了在得出相同结果的情况下减少计算的次数。这也正是算法学习的巧妙之处。