NOJ-1541-加1乘2平方

192 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

加1乘2平方

描述

给定两个正整数m、n,问只能做加1、乘2和平方这三种变化,从m变化到n最少需要几次

输入

输入两个10000以内的正整数m和n,且m小于n

输出

输出从m变化到n的最少次数

输入样例

1 16

输出样例

3

方法1:

思路:

设定dp[i]表示从m到达i最少需要i步。初始化dp[]无穷大,显然dp[m]=0,即到起点的步数为0。对于i来讲可以到达i的只有三种状态:i-1、i/2、sqrt(i)(其中i/2和sqrt(i)需要满足整数条件)。这也是基于i整体单增的条件才满足动态规划。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 10000 + 50;
int dp[maxn], n,m;
int min(int x,int y){
    if(x<=y)return x;
    return y;
}
int main(){
    cin >> m >> n;
    memset(dp, 0x3f3f3f3f, sizeof(dp));
    dp[m] = 0;
    for (int i = m + 1; i <= n;i++){
        int t = sqrt(i);
        dp[i] = min(dp[i], dp[i - 1]+1);
        if(i%2==0)
            dp[i] = min(dp[i], dp[i / 2]+1);
        if(t*t==i)
            dp[i] = min(dp[i], dp[t] + 1);
    }
    cout << dp[n] << endl;
    return 0;
}

方法2:

思路:

按照一般的方法进行BFS。一个点i往后搜索,它可以到达三个状态:i+1,i * 2,i * i,并且相应的步数+1.对于一个状态i如果已经到达过了就没必要再进行搜索了,因为第一次到达它的时候所耗步数一定是最小的,因为BFS本身就是层次遍历,一定是步数小的执行,所以只需要处理第一次到达的情况。并且在BFS的同时把到达过的点都标记了,避免重复搜索。一旦到达n就可以直接输出答案了,当然continue继续也没错。

网上的代码感觉基本雷同。所以这里写了两个方法,一个递推另一个队列+BFS(一般bfs都是配队列,当然优先队列有时效果更佳)。当然这里显然用递推是最简单的,而且O(n)的时间复杂度明显比bfs快。(测试数据:1 1000000)。

ps:if(now.now>=n||vis[now.now])continue;这里顺序不要调换,不然运行错误了找半天错。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 10000 + 50;
struct Node{
    int now, w;
};
int min(int x,int y){
    if(x<=y)return x;
    return y;
}
int n, m,vis[maxn];queue<Node>q;
int main(){
    cin >> m >> n;
    Node now;
    now.now = m;
    now.w = 0;
    q.push(now);
    int ans=0x3f3f3f3f;
    while(!q.empty()){
        now= q.front();q.pop();
        if(now.now==n){
        	ans=min(ans,now.w);continue;
		}
        if(now.now>=n||vis[now.now])continue;
        vis[now.now]=1;
        Node nex;nex.now=now.now+1;nex.w=now.w+1;q.push(nex);
		nex.now=now.now*2;nex.w=now.w+1;q.push(nex);
		nex.now=now.now*now.now;nex.w=now.w+1;q.push(nex); 
    }
    cout<<ans<<endl;
    return 0;
}