题目要求将两个数字
(
a
,
b
)
(a, b)
(a,b) 通过按钮操作转换成目标数字
(
A
,
B
)
(A, B)
(A,B)
有两种操作:
红色按钮:两个数字同时加1
蓝色按钮:两个数字同时乘2
使用DFS搜索所有可能的操作序列,找到最短的有效序列
剪枝条件:
如果当前数字超过目标数字,则无效
如果当前步数超过已知最小步数,则停止搜索
如果只有一个数字达到目标而另一个没有,则无效
代码
#include<iostream>usingnamespace std;constint INF =999999;int minSteps = INF;voiddfs(int a,int b,int A,int B,int step){// 剪枝条件if(a > A || b > B || step >= minSteps)return;if((a == A && b != B)||(b == B && a != A))return;// 找到解if(a == A && b == B){
minSteps =min(minSteps, step);return;}// 尝试两种操作dfs(a *2, b *2, A, B, step +1);// 蓝色按钮dfs(a +1, b +1, A, B, step +1);// 红色按钮}intmain(){int a, b, A, B;
cin >> a >> b >> A >> B;dfs(a, b, A, B,0);
cout <<(minSteps == INF ?-1: minSteps)<< endl;return0;}
importjava.util.*;publicclassMain{staticfinalintINF=999999;staticint minSteps =INF;staticvoiddfs(int a,int b,intA,intB,int step){// 剪枝条件if(a >A|| b >B|| step >= minSteps)return;if((a ==A&& b !=B)||(b ==B&& a !=A))return;// 找到解if(a ==A&& b ==B){
minSteps =Math.min(minSteps, step);return;}// 尝试两种操作dfs(a *2, b *2,A,B, step +1);// 蓝色按钮dfs(a +1, b +1,A,B, step +1);// 红色按钮}publicstaticvoidmain(String[] args){Scanner sc =newScanner(System.in);int a = sc.nextInt();int b = sc.nextInt();intA= sc.nextInt();intB= sc.nextInt();dfs(a, b,A,B,0);System.out.println(minSteps ==INF?-1: minSteps);}}
defdfs(a, b, A, B, step, min_steps):# 剪枝条件if a > A or b > B or step >= min_steps[0]:returnif(a == A and b != B)or(b == B and a != A):return# 找到解if a == A and b == B:
min_steps[0]=min(min_steps[0], step)return# 尝试两种操作
dfs(a *2, b *2, A, B, step +1, min_steps)# 蓝色按钮
dfs(a +1, b +1, A, B, step +1, min_steps)# 红色按钮
a, b, A, B =map(int,input().split())
min_steps =[float('inf')]# 使用列表存储最小步数,便于在递归中修改
dfs(a, b, A, B,0, min_steps)print(-1if min_steps[0]==float('inf')else min_steps[0])
算法及复杂度
算法:深度优先搜索(DFS)+ 剪枝
时间复杂度:
O
(
2
n
)
\mathcal{O}(2^n)
O(2n) - 每步有两种选择,但实际因为剪枝会小很多
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n) - 递归调用栈的深度,
n
n
n 为最小操作步数