题目描述:
http://poj.org/problem?id=3134
中文大意:
给定 x 和 n,求 xn ,要求只能使用乘法和除法,可以利用已经计算出来的结果。
问最少算多少次就够了。
思路:
x 的乘除运算,相当于指数的加减运算。
故此题等价于从数字 1 开始,在只使用加减法的情况下,问最少算多少次可以得到 n。
这题的麻烦之处在于,每步搜索产生的新值数量越来越多,增长极快,故需要限制搜索深度,以及及时剪枝。
IDA* = IDDFS + A*
①IDDFS:指定递归深度,每次做深搜时,都不会超过这个深度。
②A*:使用估价函数进行剪枝。
③估价函数:如果当前的值用最快的方式(连续乘 2,倍增)都不能计算得到 n,则停止搜索过程。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int results[1000];//所有计算过程的结果
int depth;//DFS深度
bool have_result;//是否有解
//num:计算次数
//depth:DFS深度
void dfs(int num, int depth){
//剪枝:
//1.超过规定深度
if(num > depth){
return;
}
//2.已经有解
if(have_result){
return;
}
//3.估价函数:用最快的倍增都不能到达 n
if(results[num]<<(depth-num) < n){
return;
}
//4.通过计算得到了 n
if(results[num] == n){
have_result = true;
return;
}
//尝试对之前的计算结果进行加或减操作
num++;
for(int i=0;i<num;i++){
results[num] = results[num-1] + results[i];
dfs(num, depth);
results[num] = abs(results[num-1] - results[i]);
dfs(num, depth);
}
num--;
}
int main(){
while(scanf("%d", &n) && n){
memset(results, 0, sizeof(results));
results[0] = 1;
have_result = false;
//逐渐增加深度
for(depth=0;;depth++){
dfs(0, depth);
if(have_result){
break;
}
}
printf("%d
", depth);
}
}