做法一,入门级dp,转移方程:
dp[i] = min(dp[i],dp[i/2]+1,dp[i+1]+1); //i为偶数
dp[i] = min(dp[i],dp[i+1]+1);//i为奇数
由于转移方程涉及两个方向,故选用类似于冒泡排序的while套for双重循环
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 10050
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int len = max(n,m*2);
int dp[maxn*2];
for(int i=0;i<len+1;i++) dp[i] = maxn;
dp[n] = 0;
bool flag = true;
while(flag)
{
flag = false;
for(int i=len-1;i>0;i--)
if(dp[i] > dp[i+1] + 1)
{
flag = true;
dp[i] = dp[i+1] +1;
}
for(int i=2;i<len+1;i+=2)
if(dp[i] > dp[i/2]+1)
{
flag = true;
dp[i] = dp[i/2]+1;
}
}
printf("%d\n",dp[m]);
return 0;
}
做法二,入门级dfs,需要加入数组来剪枝:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 10050
int ans[maxn*2];
void dfs(int loc,int key,int step)
{
if(loc<=0) return ;
if(step>ans[loc]) return ;
ans[loc] = step;
if(loc > key){dfs(key,key,step+loc-key);return ;}
if(loc == key){ans[key] = min(ans[key],step);return ;}
dfs(loc-1,key,step+1);
dfs(loc*2,key,step+1);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(ans,0,sizeof(ans));
for(int i=0;i<max(n,m*2)+1;i++) ans[i] = maxn;
ans[n] = 0;
dfs(n,m,0);
printf("%d\n",ans[m]);
return 0;
}
做法三,贪心,逆向思维,若m/2或(m+1)/2大于n时,先采用除2:
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 10050
int main()
{
int n,m;
scanf("%d%d",&n,&m);
if(n>=m)
{
printf("%d\n",n-m);
return 0;
}
int ans=0;
while(m>0)
{
if(m&1)
{
ans++;
m = m+1;
}
if(m/2 <= n)
{
printf("%d\n",ans+1+n-m/2);
return 0;
}else
{
ans++;
m = m/2;
}
}
return 0;
}
做法四,bfs