主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路
本题由于数据范围都在1e5以内,所以算法随便做了。
那么最简单的不费脑子的做法就是直接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;
}