当青训营遇上码上掘金-寻友之旅

48 阅读2分钟

主题 3:寻友之旅

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

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

思路

本题由于数据范围都在1e5以内,所以O(n)O(n)算法随便做了。

那么最简单的不费脑子的做法就是直接bfs,由于bfs的性质,那么第一次bfs到小青遇到小码的既是最快的时间。

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int main() {
  int n,k;
  cin>>n>>k;
  queue<pair<int,int>>q;
  q.push({n,0});
  int mintime=INT_MAX;
  vector<bool>vis(1e5,0);
  while(1){
    pair<int,int> now=q.front();q.pop();
    if(vis[now.first]) continue;
    vis[now.first]=1;
    if(now.first==k){
        mintime=now.second;
        break;
    }
    if(now.first>0&&now.first<=1e5) q.push({now.first-1,now.second+1});
    if(now.first<1e5) q.push({now.first+1,now.second+1});
    if(now.first<k) q.push({now.first*2,now.second+1});
  }
  cout<<"最小时间为:"<<mintime;
  return 0;
}

但是在看完题后,仔细想想:

  • 当小码在小青后面:
    此时只能通过步行一步步移过去
  • 当小码在小青前面:
    此时公交和步行均可,假设小码当前在k,那么当 n小于k/2 时,小青坐一次公交车肯定比走路更优,因此小青坐公交直到 n大于k/2且小于k。 此时,最小时间为min(k-n,2*n-k),当k=1.5n 时二者相等,因此当k>1.5n时坐车再走到小码的位置,否则直接走路。
  • 令dp[i]表示小青到i点的最小距离,我们可以通过动态规划来找到到达k点的最小时间。

    #include<iostream>
    #include<vector>
    using namespace std;
    int n,k;
    int main() {  
      cin>>n>>k;
      if(n>k) {
        cout<<"mintime="<<abs(n-k);
      }
      else{
        vector<int>dp(1e5+2,INT_MAX-1);
        int last=-1;
        for(int i=n;i<=1e5;++i) {
            dp[i]=min(dp[i],last+1);
            if((i<<1)<=1e5) dp[i<<1]=min(dp[i<<1],dp[i]+1); 
            last=dp[i];
        }
        for(int i=1e5;i>=n;--i){
            dp[i]=min(dp[i],dp[i+1]+1);
        }
        cout<<"mintime="<<dp[k];
      }
      return 0;
    }