UVa1374/LA3621 Power Calculus
UVa1374/LA3621 Power Calculus
- 题目链接
- 题意
- 输入格式
- 输出格式
- 分析
- AC 代码
题目链接
本题是2006年icpc亚洲区域赛日本横滨(Yokohama)赛区的F题
题意
输入正整数 n(1≤n≤1000),问最少需要几次乘除法可以从xxx得到xnx^nxn?例如,x31x^{31}x31需要 6 次:x2=x×x,x4=x2×x2,x8=x4×x4,x16=x8×x8,x32=x16×x16,x31=x32÷xx^2 = x×x, x^4 = x^2×x^2, x^8 = x^4×x^4, x^{16} = x^8×x^8, x^{32} = x^{16}×x^{16}, x^{31} = x^{32}÷xx2=x×x,x4=x2×x2,x8=x4×x4,x16=x8×x8,x32=x16×x16,x31=x32÷x。计算过程中x的指数应当总是正整数(如 x−3=x/x4x^{-3}=x/x^4x−3=x/x4是不允许的)。
输入格式
输入包含多组数据,每组数据只有一行,为一个整数 n,输入以 0 结束。
输出格式
对于每组测试数据,输出一行,输出一个最少需要的乘除次数。
分析
用IDA*来做,基于贪心来构造启发函数:在当前计算出的指数序列的最大值为 x,已经计算了 s 步,最多计算 d 步的情况下,如果 x×2d−s<nx\times 2^{d-s} < nx×2d−s<n,则必然无法得到 n,剪枝。
还有如下优化策略:
- 每次总是使用上一步得出的数进行加减操作(只需再从整个序列枚举出另外一个数)。
- 超过 n 的数最多只需要一个。
- 先考虑加法再考虑减法。
AC 代码
#include <iostream>
using namespace std;#define M 20
short a[M], n, ans;bool iddfs(short v = 1, short m = 1, short d = 0) {if (d == ans) return v == n;if (m << (ans-d) < n) return false;for (short i=0; i<=d; ++i) {short v1 = v + a[i];if (m<n || v1<=n) {a[d+1] = v1;if (iddfs(v1, max(m, v1), d+1)) return true;}v1 = abs(v - a[i]);if (v1>0 && (m<n || v1<=n)) {a[d+1] = v1;if (iddfs(v1, max(m, v1), d+1)) return true;}}return false;
}int main() {a[0] = 1;while (cin>>n && n) {for (ans=0; !iddfs(); ++ans);cout << ans << endl;}return 0;
}