搜索—Power Calculus
Description
从 x 开始,通过反复乘以 x,我们可以使用 30 次乘法来计算 x31:
x2 = x × x, x3 = x2 × x, x4 = x3 × x, …, x31 = x30 × x.
平方操作可以显著缩短乘法序列。以下是使用八次乘法来计算 x31 的一种方法:
x2 = x × x, x3 = x2 × x, x6 = x3 × x3, x7 = x6 × x, x14 = x7 × x7, x15 = x14 × x, x30 = x15 × x15, x31 = x30 × x.
这不是计算 x31 最短乘法序列。有许多只需要七次乘法的方法。以下是其中一种:
x2 = x × x, x4 = x2 × x2, x8 = x4 × x4, x8 = x4 × x4, x10 = x8 × x2, x20 = x10 × x10, x30 = x20 × x10, x31 = x30 × x.
如果除法也可用,我们可以找到一种更短的操作序列。可以使用六次操作(五次乘法和一次除法)来计算 x31:
x2 = x × x, x4 = x2 × x2, x8 = x4 × x4, x16 = x8 × x8, x32 = x16 × x16, x31 = x32 ÷ x.
如果除法和乘法一样快,这是计算 x31 最有效的方法之一。
你的任务是编写一个程序,为给定的正整数 n,通过乘法和除法从 x 开始计算 xn 所需的最少操作次数。序列中出现的乘积和商应为 x 的某个正整数次幂。换句话说,不应出现 x−3 等。
Input
输入是一个包含一个或多个整数 n 的序列。n 为正且小于等于 1000。输入以零结束。
Output
你的程序应打印出从 x 开始计算整数 n 的 xn 所需的最少总乘法和除法次数。每个数字应写在单独的一行中,不应包含任何多余的字符,如前导或尾随空格。
Sample Input
1
31
70
91
473
512
811
953
0
Sample Output
0
6
8
9
11
9
13
12
More Info
分析
对于题目中的乘除操作,我们只需要考虑指数的加减,对结果进行搜索,将搜索一颗巨大的多叉树,所以这里我们采用IDA*算法进行优化搜索,每次搜索固定的深度,利用最直接的方法倍增,看能否在固定深度内够到xn,不能则剪枝,把这一判断作为评估函数。
代码实现
#include<stdio.h>
#include<string.h>
const int N = 100; //最大层次
int num[N]; //记录一条路径上的数字,num[i]是路径上第i层的数字
int n, depth;
bool dfs(int now, int d) { //now:当前路径走到的数字,d:now所在的深度
if (d > depth) return false; //当前深度大于层数限制
if (now == n) return true; //找到目标。注意:这一句不能放在上一句前面,因为输出的是层数,放到上面会少一层
if (now << (depth - d) < n) //剪枝:剩下的层数用最乐观的倍增也不能达到n
return false;
num[d] = now; //记录这条路径上第d层的数字
for(int i = 0; i <= d; i++) { //遍历之前算过的数,继续下一层
if (dfs(now + num[i], d + 1)) return true; //加
else if (dfs(now - num[i], d + 1)) return true; //减
}
return false;
}
int main() {
while(~scanf("%d", &n) && n) {
for(depth = 0;; depth++) { //IDDFS:每次限制最大搜索depth层
memset(num, 0, sizeof(num));
if (dfs(1, 0)) break; //从数字1开始,当前层0
}
printf("%d\n", depth);
}
return 0;
}

浙公网安备 33010602011771号