题意:给定数x和n,求x的n次方,只能用乘法和除法,算过的过程可以被利用。问最少多少次就够了。
(输入只有n,n<=1000)
这一题等价与从数字1开始,用加减法,最少多少次得到n。
思路:用IDDFS,并用估价函数进行剪枝;
(1)IDDFS:指定递归深度,每一次做递归时不超过这个深度,(这个深度得到的结果一定最优,否则在上一个深度就已经结束搜索了,所以一定是最深时才得到n)
(2)估价函数:如果当前的值用最快的方式(连续乘2,倍增)都不能到达(大于等于)n,停止这个值继续DFS(因为当前认为depth步是最优的,而倍增(depth-now)次挨都挨不到n,这个值就没必要了)
(3)下一个数=上一个数与前面所有的数相加,之所以这样,我个人认为有时存在几个连续的数倍增多次(到达最深时)都是大于或等于n的,可能加上不是最大的数后倍增多次会恰好等于n。(相减的应该差不多)
代码:
#include<iostream> #include<cmath> using namespace std; int val[1010]; //保存一个搜索路径上每一步的计算结果 int pos,n; bool ida(int now,int depth){ if(now>depth) return false;//IDDFS:大于当前设定的DFS深度,退出 if((val[pos] << (depth-now))< n) return false; //评估函数:用最快的倍增都不能到达n,退出 if(val[pos]==n) return true;//当前结果是n,退出 pos++; for(int i=0;i<pos;i++){ val[pos]=val[pos-1]+val[i];//上一个数与前面所有的数相加 if(ida(now+1,depth)) return true; val[pos]=abs(val[pos-1]-val[i]);//上一个数与前面所有的数相减 if(ida(now+1,depth)) return true; } pos--; return false; } int main(){ while(cin>>n&&n){ int depth; for(depth=0;;depth++){ //每次只DFS到深度depth val[pos=0]=1; //初始值都是1 if(ida(0,depth)) break;//每次都是从0开始DFS到第depth层 } cout<<depth<<endl; } return 0; }
(一天都没搞懂,求助钟涛大佬,大佬一下就思路通透了,tql)