首页 > 试题广场 >

求x到y的最少计算次数

[编程题]求x到y的最少计算次数
  • 热度指数:3220 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定两个-100到100的整数x和y,对x只能进行加1,减1,乘2操作,问最少对x进行几次操作能得到y?
例如:
a=3,b=11: 可以通过3*2*2-1,3次操作得到11;
a=5,b=8:可以通过(5-1)*2,2次操作得到8;


输入描述:
输入以英文逗号分隔的两个数字,数字均在32位整数范围内。


输出描述:
输出一个数字
示例1

输入

3,11

输出

3
#include <bits/stdc++.h>
using namespace std;

int x,y;

void BFS(){
    map<int,bool> vis;
    queue<pair<int,int>> q;
    q.push({x,0});
    vis[x] = false;
    while(!q.empty()){
        pair<int,int> p = q.front();
        q.pop();
        int t = p.first, cnt = p.second;
        if(t==y){
            cout<<p.second<<endl;
            return;
        }
        if(vis.find(t+1)==vis.end()){
            q.push({t+1, cnt+1});
            vis[t+1] = true;
        }
        if(vis.find(t-1)==vis.end()){
            q.push({t-1, cnt+1});
            vis[t-1] = true;
        }
        if(vis.find(2*t)==vis.end()){
            q.push({2*t, cnt+1});
            vis[2*t] = true;
        }
    }
}

int main(){
    scanf("%d,%d", &x, &y);
    BFS();
    return 0;
}

发表于 2019-08-31 01:45:26 回复(0)
#bfs这是一个最小路径的搜索问题,第一时间想到这个,这里多加了一列用来储存位置
def bfs(quene,b):
    while quene:
        x = quene.pop(0)
        if x[0]==b:
            return x[1]
        else:
            quene.append([x[0]+1,x[1]+1])
            quene.append([x[0]-1,x[1]+1])
            quene.append([x[0]*2,x[1]+1])


if __name__=="__main__":
    a,b = map(int,input().strip().split(','))
    quene = []
    quene.append([a,0])
    print(bfs(quene,b))

发表于 2019-07-29 18:51:07 回复(0)
#include <iostream>
#include <deque>
#include <unordered_set>

using namespace std;

int breadth_first_search_algorithm(int s, int t) {
  deque<int> q{{s}};
  unordered_set<int> seen{s};
  
  int steps = 0;
  while (not q.empty()) {
    size_t s = q.size();
    while (s--) {
      const int curr = q.front(); q.pop_front();
      if (curr == t) return steps;
      for (const int nxt : {curr - 1 , curr + 1, curr << 1}) {
        if (!seen.emplace(nxt).second) continue;
        q.emplace_back(nxt);
      }
    }
    ++steps;
  }
  
  return -1;
}

int main(const int argc, const char* const argv[]) {
  ios::sync_with_stdio(false);
  cin.tie(0);
  
  int x, y;
  fscanf(stdin, "%d,%d", &x, &y);
  cout << breadth_first_search_algorithm(x, y);
  return 0;
}

发表于 2021-08-05 14:19:13 回复(0)
import java.util.*;

public class Main {
    
    public static void main(String[] args) {
        
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] nums = s.split(",");
        int a = Integer.parseInt(nums[0]);
        int b = Integer.parseInt(nums[1]);
        
        int ans = solution(a,b);
        System.out.println(ans);
    }
    
    private static int solution(int a, int b){
        
        int ans = 0;
        // 特殊值
            if(a == 0 && b <= 0) return Math.abs(b);
            if(a == 0 && b > 0) return minOps(1,b) + 1;

        // a b 同号
        if(a * b > 0){
            a = Math.abs(a); b = Math.abs(b);
            if(a >= b) return a - b;
            // a < b
            else return minOps(a,b);
        } 
        // a b 异号
        // 如果 a 是负值,将 a 转换为正值 1,则 a * b > 0,调用自身得到结果。
        if(a < 0) return ans - a + 1 + solution(1,b);
        // 如果 b 是负值,将 b 转换为正值 1。
        return ans - b + 1 + solution(a,1);
    }
    
    private static int minOps(int a, int b){

        if(b >= a && b <= (a << 1))
            return Math.min(b - a,(a << 1) - b + 1);
        if((b & 1) == 1)
            return Math.min(minOps(a,(b + 1) >> 1), minOps(a,(b - 1) >> 1)) + 2;
        return minOps(a,b >> 1) + 1;
    }
}

编辑于 2020-07-12 15:46:38 回复(0)
动态规划,时间复杂度O(n),从后往前、从前往后各扫描一遍。要注意x可能大于y。
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <string>
#include <math.h>

using namespace std;
int dp[210];
int max_depth=210;

int trans(int x,int y){
    if(x>=y){
        return x-y;
    }
    dp[y]=0;
    dp[y+1]=1;
    dp[y-1]=1;
    int cur;
    for(int i=y-2;i>=0;i--){
        dp[i]=dp[i+1]+1;
        if(i*2<=y+1){
            dp[i]=min(dp[i*2]+1,dp[i]);
        }
    }
    for(int i=1;i<=y-2;i++){
        dp[i]=min(dp[i-1]+1,dp[i]);
        if(i%2==0){
            dp[i]=min(dp[i/2]+1,dp[i]);
        }
    }
    return dp[x];
}
int main() {
    int x,y;
    char ch;
    cin>>x>>ch>>y;
    for(int i=0;i<max_depth;i++){
        dp[i]=max_depth;
    }
    int return_res=0;
    if(x<0 and y<0){
        x=-x;
        y=-y;
    }
    else if(x<0 and y>0){
        return_res-=x;
        x=0;
    }
    else if(x>0 and y<0){
        return_res+=x;
        x=0;
        y=-y;
    }
    return_res+=trans(x,y);

    cout<<return_res;
    return 0;
}


编辑于 2020-05-21 10:40:48 回复(1)
import java.util.*;
public class Main{
    //该题考的是广度优先遍历,我用的广度优先遍历是左神基础课中教的方法
   static class Node{
        private int value; //结的值
        private int depth;//结点的深度
        private ArrayList<Node> nodes;//子结点
       //构造函数
        public Node(int value,int depth){
            this.value = value;
            this.depth = depth;
        }
    }
    public static void main(String[] args){
        //获取a,b的值
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        int a = Integer.parseInt(str.split(",")[0]);
        int b = Integer.parseInt(str.split(",")[1]);
        //存入头结点,并初始化队列和hashSet
        Node head  = new Node(a,0);
        Queue<Node> queue = new LinkedList<>();
        HashSet<Node> set = new HashSet<>();
        queue.add(head);
        set.add(head);
        while(!queue.isEmpty()){
            head = queue.poll();
            //找到该值后,输出并结束main()方法
            if(head.value == b){
                System.out.println(head.depth);
                return;
            }else{
                //没有找到该值,则在这个节点后面添加3个子结点,分别是值+1,值-1,值*2. 结点的深度+1;
                ArrayList<Node> nodes = new ArrayList<>();
                nodes.add(new Node(head.value+1,head.depth+1));
                nodes.add(new Node(head.value-1,head.depth+1));
                nodes.add(new Node(head.value*2,head.depth+1));
                head.nodes = nodes;
            }
            //将当前结点的所有子结点压入队列,hashSet的作用是防止同一个结点被遍历压入队列两次.
            for(Node node : head.nodes){
                if(!set.contains(node)){
                    queue.add(node);
                    set.add(node);
                }
            }
            
        }
        
    }
}
附图:广度优先遍历
                                        3
                              /         |           \
                            2           4            6
                      /     |    \    /  |  \       /  |  \
                    1      3   4  4 3   8    5  7  12


发表于 2020-03-12 02:46:48 回复(0)
#include <bits/stdc++.h>
using namespace std;
int bfs(int x,int y,map<int,int> &m){
    queue<int> que;
    int sum=0;
    que.push(x);
    m.insert(make_pair(x,0));
    while(!que.empty()){
        int temp=que.front();
        que.pop();
        if(temp>100||temp<-100)
            continue;
        sum=m[temp];
        if(temp==y){
            break;
        }
        if(m.find(temp+1)==m.end()){
            que.push(temp+1);
            m.insert(make_pair(temp+1,sum+1));
        }
        if(m.find(temp-1)==m.end()){
            que.push(temp-1);
            m.insert(make_pair(temp-1,sum+1));
        }
        if(m.find(temp*2)==m.end()){
            que.push(temp*2);
            m.insert(make_pair(temp*2,sum+1));
        }
    }
    return sum;
}
int main(){
    int x,y;
    scanf("%d,%d",&x,&y);
    map<int,int> m;
    cout<<bfs(x,y,m);
    return 0;
}

发表于 2019-10-17 11:42:24 回复(0)
import java.util.Scanner;

public class Main {
//思路:从Y逆推,如果Y是奇数就减一(或加一,两种情况比较哪个次数少);之后让Y不断除以2,如果能变成X,就结束
    //不能则在比X小的时候停下来(如果比他它大1,偶尔也要让-1发挥一下,就停止),计算要+1多少次
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
String line = sc.nextLine();
String[] split = line.split(",");
int x=Integer.valueOf(split[0]);
int y=Integer.valueOf(split[1]);
int res ;
if(x<y&&x>0)//负数这里测试用例,只需要把它当做只能靠x+1来变化
res = Math.min(xToy(x,y,-1),xToy(x, y, 1));
else
res=Math.abs(x-y);
System.out.println(res);
}
sc.close();
}
private static int xToy(int x, int y,int plus) {
int count=0;
if(y%2!=0) {
y=y+plus;
count++;
}
while(y>x) {
y=y/2;//要整除,不整除向下取整
count++;
if(y-1==x){return count+1;}
}
count+=x-y;//x-y是当y小于x的时候,两者的差值
return count;
}
}
编辑于 2019-09-10 10:34:00 回复(1)
//bfs
#include <bits/stdc++.h>
using namespace std;
 
int a, b;
char c;
int bfs()
{
    queue<pair<int, int>> q;
    map<int, int>ma;
   q.push({ a,0 });
    while (!q.empty())
    {
        pair<int,int> t = q.front(); q.pop();
        if (ma.count(t.first) == 1)
            continue;
        ma[t.first] = 1;
        if (t.first == b)
            return t.second;
        q.push({ t.first + 1,t.second + 1 });
        q.push({ t.first - 1,t.second + 1 });
        q.push({ t.first * 2,t.second + 1 });
    }
    return 0;
}
 
int main()
{
    while (cin >> a >> c >> b)
    {
        cout << bfs() << endl;
    }
  
    return 0;
}
编辑于 2019-04-26 11:19:46 回复(0)
#include <bits/stdc++.h>

using namespace std;

map<int,int> dp;

int Min(int x, int y, int z, int k) {
	return min(min(x, k), min(y, z));
}

int main() {
	int x, y;
	scanf("%d,%d", &x, &y);
	for (int i = -400 ; i <= 400; i++) {
		dp[i] = 1000000;
	}
	dp[y] = 0;
	for (int i = 200; i >= -200; i--) {
		for (int j = 200; j >= -200; j--) {
			dp[j] = Min(dp[j - 1] + 1, dp[j + 1] + 1, dp[j * 2] + 1, dp[j]);
		}
	}
	cout << dp[x] << "\n";
	return 0;
}

发表于 2019-11-27 20:01:46 回复(6)
开始想的动态规划  题目知识点里面给的关键词队列  那就直接BFS暴力了
#include<bits/stdc++.h>
using namespace std;
int x, y;
queue<int> qu;

int solve() {
    if(x == y) return 0;
    qu.push(x);
    int cnt = 0, size = 1;
    while(!qu.empty()) {
        cnt++;
        int size = qu.size();
        for(int i = 0; i < size; i++) {
            int t = qu.front(); qu.pop();
            if(t + 1 == y || t - 1 == y || t*2 == y) return cnt;
            if(t + 1 <= 100) qu.push(t + 1);
            if(t - 1 >= -100) qu.push(t - 1);
            if(2 * t <= 200 && 2 * t >= -200) qu.push(2*t);
        }
    }
}

int main() {
    scanf("%d,%d", &x, &y);
    cout<<solve()<<endl;
}
/*
3,11
*/


发表于 2020-02-11 17:56:49 回复(0)
深度优先遍历
import java.util.Scanner;

public class Main {
    
    static Scanner sc = new Scanner(System.in);
    static String s[] = sc.next().split(",");
    static int x = Integer.valueOf(s[0]);
    static int y = Integer.valueOf(s[1]);
    static int upBound = Math.abs(x - y);          // 操作数最小值的上界
    
    public static void main(String[] args) {
        dfs(x, y, 0);
        System.out.println(upBound);
    }
 
    private static void dfs(int x, int y, int count) {
        // 如果到了操作数的上界,直接返回
        if (count == upBound)
            return;
        // 如果两数相等,直接返回
        if (x == y){
            upBound = count;
            return;
        }
        // 否则遍历三种操作
        dfs(x + 1, y, count + 1);
        dfs(x - 1, y, count + 1);
        dfs(x * 2, y, count + 1);
    }
}


发表于 2020-10-27 10:50:19 回复(0)
深度优先搜索
import java.util.Scanner;

/**
 * @Author: coderjjp
 * @Date: 2020-05-09 18:27
 * @Description:
 * @version: 1.0
 */
public class Main {
    static Scanner sc = new Scanner(System.in);
    static String s[] = sc.next().split(",");
    static int x = Integer.valueOf(s[0]);
    static int y = Integer.valueOf(s[1]);
    static int min = Math.abs(x - y);//最小值的上界
    public static void main(String[] args) {
        dfs(x, y, 0);
        System.out.println(min);
    }

    private static void dfs(int x, int y, int count) {
        if (count == min)
            return;
        if (x == y){
            min = count;
            return;
        }
        dfs(x + 1, y, count + 1);
        dfs(x - 1, y, count + 1);
        dfs(x * 2, y, count + 1);
    }
}

发表于 2020-05-09 19:48:34 回复(1)

-100,100怎么说?Java用BFS直接OOM

发表于 2022-12-18 12:40:55 回复(0)
发表于 2022-05-18 17:04:34 回复(0)
Java递归做法:首先需要把输入的两个数都变成正数(否则会Stackoverflow),如果两数异号则直接将第一个数归零,结果加上第一个数的绝对值。
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] s = sc.nextLine().split(",");
        int a = Integer.parseInt(s[0]);
        int b = Integer.parseInt(s[1]);
        int res = 0;
        if(a*b<0){
            res = Math.abs(a);
            a = 0;
        }
        a=Math.abs(a);
        b=Math.abs(b);
        System.out.print(helper(a,b,res));
    }
    public static int helper(int a, int b, int res){
        if(a==b) return res;
        if(a!=0 && Math.abs(2*a+2)<Math.abs(b)) return Math.min(helper(a+1,b,res+1),helper(a*2,b,res+1));
        else if(Math.abs(a+1-b)<Math.abs(a-1-b) && Math.abs(a+1-b)<Math.abs(a*2-b)) return helper(a+1,b,res+1);
        else if(Math.abs(a+1-b)>Math.abs(a-1-b) && Math.abs(a-1-b)<Math.abs(a*2-b)) return helper(a-1,b,res+1);
        else return helper(a*2,b,res+1);
    }
}

发表于 2020-05-05 08:15:52 回复(0)
//本题不太适合用dfs,但看讨论里没有dfs写法,还是加一个;
#include <iostream>

using namespace std;

int result = 200;

void dfs(int x, int y, int step){

    if(step>result){
        return;
    }
    if(x==y){
        result = min(result, step);
        return;
    }

    if(x<y){
        dfs(x+1, y, step+1);
    }
    else{
        dfs(x-1, y, step+1);
    }
    dfs(2*x, y, step+1);

    return;
}

int main(){

    int x, y;
    char c;
    while(cin >> x >> c >> y){

        result = 200;
        dfs(x, y, 0);
        cout << result << endl;

    }
    return 0;
}
发表于 2020-03-28 15:25:26 回复(0)
宽度优先搜索,用队列,把每次可能的结果放进队列。优化技巧,只有在 0 ~ 100的数,以及没出现过的数,才入队列。
import java.util.LinkedList;
import java.util.Scanner;

/**
 * @author lihaoyu
 * @date 2019/12/28 14:21
 */
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String next = scanner.next();
        int x = Integer.parseInt(next.split(",")[0]);
        int y = Integer.parseInt(next.split(",")[1]);
        if(y <= x){
            System.out.println( x - y);
            return;
        }
        if(y <= 0){
            System.out.println(Math.abs(x - y));
            return;
        }
        int count = 0;
        if( x <= 1){
            count += 1 - x;
            x = 1;
        }
        LinkedList<Integer> list = new LinkedList<>();
        list.addLast(x);
        // 用来记录有没有出现过
        boolean[] flags = new boolean[101];
        while(true){
            // 先查一下有没有
            if(list.contains(y)){
                System.out.println(count);
                return;
            }
            int len = list.size();
            count++;
            for(int i = 0; i < len; i++){
                Integer temp = list.pollFirst();
                if(temp - 1 > 0 && temp - 1 <= 100 && !flags[temp-1]) {
                    list.addLast(temp-1);
                    flags[temp-1] = true;
                }
                if(temp + 1 > 0 && temp + 1 <= 100 && !flags[temp+1]) {
                    list.addLast(temp+1);
                    flags[temp+1] = true;
                }
                if(temp * 2 > 0 && temp * 2 <= 100 && !flags[temp*2]) {
                    list.addLast(temp*2);
                    flags[temp*2] = true;
                }
            }
        }

    }
}

发表于 2019-12-28 14:51:14 回复(0)
广度优先遍历,和路径规划算法差不多
#include <iostream>
#include <istream>
#include <vector>
using namespace std;

vector<int> record;
long ans = 0;

void bfs(int target){
    
    ans++;
    int num = record.size();
    for(int i = 0; i<num; i++){
        if(record[i]+1 == target || record[i]-1 == target || record[i]*2 == target){
            return;
        }
        record.push_back(record[i]+1);
        record.push_back(record[i]-1);
        record.push_back(record[i]*2);
    }
    
    record.erase(record.begin(), record.begin()+num-1);
    bfs(target);
}

int main(){
    int x, y;
    char ch;
    cin >> x;
    record.push_back(x);
    cin >> ch;
    cin >> y;
    
    if(x == y){
        cout << 0;
        return 0;
    }
    
    bfs(y);
    
    cout << ans;
    
    return 0;
}


发表于 2019-09-18 10:16:26 回复(0)
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;

int main() {
    int x, y;
    int cnt = 0;
    bool flag = false;
    scanf("%d,%d", &x, &y);
    queue<int> q;
    q.push(x);
    while (!q.empty()) {
        int len = q.size();
        for (int i = 0; i < len; i++) {
            int tmp = q.front();
            q.pop();
            if (tmp == y) {
                flag = true; 
                break;
            } else {
                q.push(tmp + 1);
                q.push(tmp - 1);
                q.push(tmp * 2);
            }
        }
        if (flag)
            break;
        cnt++;
    }
    cout << cnt << endl;
    return 0;
}

发表于 2019-09-04 11:04:25 回复(0)