- 问题描述:
关于整数i的变换f和g定义如下:f(n)=3*n;g(n)=[n/2];试设计一个算法,对于给定的两个整数n和m,用最少的f和g变换次数将n转化为m。
- 算法设计:
对任意给定的整数n和m,计算将整数n转换成m所需要的最少变换次数。
- 数据输入:
由文件input.txt给出输入数据。第一行有2个正整数n和m。
- 结果输出:
将计算的最少变换次数以及相应的变换序列输出到文件output.txt。
文件的第一行是最少变换次数,第2行是相应的变换序列。
输入文件:
input.txt
15 4
output.txt
4
gfgg
循环样例:9 5
- 思路:
可以当一个子集树,每次都有两种选择:g(n)和f(n);但是每次递归的n的值都是刚刚计算出来的新的值。
- 剪枝函数:
如果n>=m,执行g(n)=[n/2]; 如果n<m,执行f(n)=3*n;
如果加了剪枝函数,就会使得求出来的只可能有一种情况,这种一定是最少变换次数。
import java.util.Scanner;
public class ZSBH {
public static int m = -1;// 用于存放最后要变成的值
public static int n = -1;// 用于存放刚开始的值
public static char[] zt = new char[100];// 存放状态
public static int[] zhi = new int[100];// 存放之前每一次计算的n的值,如果后面也出现了前面的值,就说明出现了死循环。
public static int j = 0;// 来代表进入了第几次递归,从0开始
public static void backtrack(int t) {
int flag = 0;
if(t == m) {
System.out.println(t);
for(int i = 0; i < zt.length; i++) { // 此处的zt.length可替换成j
System.out.print(zt[i]+" ");
}
}
else {
// 和之前的所有值比较,看是否出现重复
for(int i = 0; i < zhi.length; i++) { // 此处的zt.length可替换成j
if(zhi[i] == t) {
System.out.println("重复了!");
flag = 1;
break;
}
}
if(flag != 1) {
zhi[j] = t;// 先把这次的值t存起来
if(t < m) {
t = 3 * t;
zt[j++] = 'f';// 记下这一次执行的是什么
}else {
t = t / 2;
zt[j++] = 'g';
}
backtrack(t);
}
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
m = input.nextInt();
backtrack(n);
}
}