【暖*墟】#迭代加深# 快速幂运算次数 uva1374

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;

/*【快速幂计算】(UVa1374)
输入正整数n(1≤n≤1000),问最少需要几次乘除法可以 { 从x得到x^n } ?
计算过程中x的指数应当总是正整数。 */

/*【分析】考虑迭代加深搜索。
当前状态是已经得到的指数集合,操作是任选两个数进行加法和减法,
并且不能产生重复的数。用d表示当前深度,maxd表示深度上限,
则当前序列最大的数乘以2^(maxd-d)之后仍小于n时,剪枝。
另外,为了尽快接近目标,应该先选较大的数,并且先试加法再试减法。
这样做可以在最后一次迭代(即找到解的那次迭代)中比较快地找到解,
从而终止整个搜索过程,而不需要等整个解答树扩展完毕。
只要比赛允许,甚至可以预先把n=1~1000范围的所有解算出来。
这样的技巧俗称“打表”。本题还有一些常见的优化,例如,限制减法的次数。
(实际上大部分时候都是最大的数乘以2),或者限制超过n的数的个数。
(事实上,可以证明最多有一个数需要超过n)。另外还有一个猜想:
每次总是使用“刚刚得到”的那个数。   */

const int maxn = 1000 + 9;
int maxd, n, a[maxn];
 
 
bool dfs(int d, int num, int cur){ //深度,该深度对应元素个数,目前值
    if(d == maxd){ //到达最后一层
        if(n == cur)  return true; //正好达到目标值
        return false;
    }
    int m = 0;
    for(int i = 0; i < num; ++i)  m = max(m, a[i]);
    if(m * (1 << (maxd - d)) < n)  return false; //【剪枝】
    for(int i = num-1; i >= 0; --i){
        a[num] = cur + a[i];  ++num; //乘法
        if(dfs(d+1, num, cur+a[i]))  return true;
        a[num-1] = abs(cur - a[i]); //除法
        if(dfs(d+1, num, abs(cur-a[i])))  return true;
        --num; //还原
    }
    return false;
}
 
int main(){
    while(scanf("%d", &n) == 1 && n){ //↓↓迭代加深
        for(maxd = 0; maxd < 13; maxd++){ //不停累加限定深度
            a[0] = 1; //起始
            if(dfs(0, 1, 1)) break;
        }
        printf("%d\n", maxd); //最终确定的深度上限
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/flora715/article/details/80987384