以下的所有观点并不完全正确,只是个人的主观理解,请读者谨慎阅读:
IDA算法:
该算法为dfs算法的变种。首先设置一个深度上界maxH,设当前深度h(x),估界函数为g(x),当且仅当 h(x) + g(x) > maxH时表示该分支不可能有解应该剪掉该分支回溯回去。 如果在当前深度上界不能得到解,则增加深度上界的值,直到得到解。
为何? 该算法得到解为最优解呢? 我个人观点:IDA算法跟普通的dfs的区别就是:“IDA*算法将 dfs要遍历的深度进行了分割,这样可以剪掉许多不必要的分支,从而比普通的dfs要快,并且在有些题目中遍历的深度与广度没有界限,很难正确的设计回溯算法,这时候就要分割深度,将深度看作一个一个的界限,然后枚举这些界限直达找到答案。” 分割深度需要找到一个合适的估计上界的函数。 一般的操作是: 求最大值则假设一个合法的最小值,然后除以剩余值得到 g(x) ;求最小值时则相反。 埃及分数就是一个“求最小值”的例子
参考紫书上的代码:
#include<iostream>
#include<string.h>
#include<algorithm>
typedef long long LL;
using namespace std;
int maxd;
LL ans[100], v[100];
int get_first(int n, int m) {
int a = 2;
while (n * a < m) a++;
return a;
}
bool compare(int floor) {
for (int i = floor; i >= 0; i--) {
if (v[i] != ans[i])
return ans[i] == -1 || v[i] < ans[i];
}
}
int gcd(int n2, int m2) {
return m2 % n2 ? gcd(m2 % n2,n2) : n2;
}
bool dfs(int floor, int fm, LL n, LL m) {
if (floor == maxd) {
if (m % n) return false;
v[floor] = m / n;
if (compare(floor)) memcpy(ans, v, sizeof(LL) * (floor + 1));
return true;
}
bool ok = false;
fm = max(fm, get_first(n, m));
for (int i = fm; ; i++) {
if (m * (maxd + 1 - floor) <= i * n) break; //估计可能还需要向下几层, 如果超过了则结束
LL n2, m2;
v[floor] = i;
n2 = n * i - m;
m2 = m * i;
LL b = gcd(n2, m2);
if (dfs(floor + 1, i + 1, n2 / b, m2 / b)) ok = true;
}
return ok;
}
void print(int floor,int n, int m) {
printf("%d/%d=1/%d", n, m,ans[0]);
for (int i = 1; i <= floor; i++) {
printf("+1/%d", ans[i]);
}
cout << endl;
}
int main() {
LL n, m;
while (cin >> n >> m) {
for (maxd = 1; ; maxd++) {//枚举所有的深度上界,如果有解则一个会有一个深度上界可以退出循环, 递归的深度就是当前深度上界。
memset(ans, -1, sizeof(ans));
if (dfs(0, get_first(n, m), n, m)) {
print(maxd, n, m);
break;
}
}
}
return 1;
}