当青训营遇上码上掘金
老老实实的开头
本篇是主题创作活动写主题3:寻友之旅写的题目
开头先降低预期
代码小白虽然写是写出来了(应该)但是时间复杂度可能有些高有些暴力没有想到优化的方法
小白谢谢大佬们轻喷如果能指出还有哪个地方可以优化就好了先谢过大佬
如有雷同,纯属巧合,我没有看任何人的题解或者是与人交流想的
题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K 输出: 小青到小码家所需的最短时间(以分钟为单位)
思考过程
读题
我们可以把题目理解成一个数轴,从0-100 000范围,小青在坐标N,小码在坐标K,只有小青能在数轴上移动
两种移动方式?其实有三种
第一种:向数轴右方移动一次 对应x+1
第二种:向数轴左方移动一次 对应x-1
第三种:使横坐标翻倍 对应x乘2
分析
请帮助小青通知小码,小青最快到达时间是多久?
最快到达,我们一般根据最快关键字,一般选用的是贪心或者动态规划来解决问题
根据平常动态规划的思想
我们可以用一个数组来存储就是到当前位置所需的最短时间
题目没有说明N是否一定大于K,所以可以分为两种情况
N>=K
小青在右,小码在左
公交车不能向后走,只能向后步行,只有向数轴左方一步步移动一种方式
所以这种情况下答案只有一种走法
花费N-K分钟
N<=K
这个我想了好久,动态转移方程,没有能想出来
如果题目只有 从左往右那这题就很简单,可惜多了x--的情况也就是说可以折回来
比如说2 到 15
2翻倍到4再到8再到16
最后折返
最短的分钟为4
最终解决方法
x++的情况
只剩N<=K情况下我们来解决问题
同样的除了2到15
还有坐标5 到 8 先返回到4再乘2只需要两分钟
我们尝试用动态规划来解决
动态规划v【i】值代表走到i所需要的最小分钟
v【i】=v【i-1】+1
代表x++的走法
代码
v[j]=v[j-1]+1;
x--和2*x的结合
还有剩下两种走法
我们可以枚举这两种走法,试图找到最小值
比如 8
可以从8/2也就是4直接跳来
或者是10/2也就是5跳来,然后从10再往回走2步
然后我们可以一直枚举到14/2的极端情况下
也就是t/2<j的情况下 不断枚举
最后代码写成
v[j]=min(v[j],v[t/2]+1+t-j);
最终代码
#include<bits/stdc++.h>
using namespace std;
int solve(int n,int k)
{
if(k<=n)
return n-k;
vector<int>v(k+3);
for(int j=1;n-j>=0;j++)
v[n-j]=j;
v[n]=0;
for(int j=n+1;j<=k;j++)
{
v[j]=v[j-1]+1;
for(int t=j%2==0?j:j+1;t<j*2;t+=2)
{
v[j]=min(v[j],v[t/2]+1+t-j);
}
}
return v[k];
}
int main()
{
int n,k;
cin>>n>>k;
cout<<solve(n,k);
return 0;
}