迭代加深搜索: 从小到大枚举深度 maxd, 每次执行只考虑深度不超过maxd的结点。这样,只要解得深度有限,则一定可以在有限的时间内枚举到(一定要有解哈)
如果可以设计出一个乐观估价函数,预测从当前结点至少还需要扩展几层结点才有可能得到解,则迭代加深搜索变成了IDA*算法
经典的埃及分数问题:
在古埃及,人们使用单位分数的和(1/a, a为自然数),表示有理数、例如2/3 = 1/2 + 1/6,但 2/3 = 1/3 + 1/3是不允许的,因为加数不允许相同
对于一个分数a/b,表示方法有很多种,其中加数少的比加数多的好,如果加数个数相同,则最小的分数越大越好。例如, 19/45 = 1/5 + 1/6 + 1/8就是最优方案。
输入: 495 499
输出:Case 1: 495/499 = 1/2 + 1/5 + 1/6 + 1/8 + 1/3992 + 1/14970
代码:
//经典的埃及分数
#include
using namespace std;
typedef long long LL;
int maxd;
int ans[1000];
int v[1000];
int a, b;
int gcd(LL a, LL b)
{
if(b == 0) return a;
else return gcd(b, a%b);
}
int get_first(int a, int b) //找到满足 1/c <= a/b 的最小的c 也就是找到满足这个条件的最大的1/c
{
int c = 1;
while(b > a*c) c++;
return c;
}
bool better(int d)
{
for(int i = d; i >= 0; i--)
{
if(v[i] != ans[i])
{
return ans[i] == -1 || v[i] < ans[i];
}
}
return false;
}
bool dfs(int d, int from, LL aa, LL bb) //当前深度为d, 分母不能小于from, 分数之和恰好是aa/bb
{
if(d == maxd)
{
if(bb % aa) return false;
v[d] = bb / aa;
if(better) memcpy(ans, v, sizeof(LL)*(d+1)); //把v里面的东西拷贝到ans里面
return true;
}
bool ok = false;
from = max(from, get_first(aa, bb)); //当前分母或者是
for(int i = from; ; i++)
{
if(bb * (maxd+1-d) <= i * aa) break; // 函数剪枝(maxd+1-d) * (1/i) <= (aa/bb)
v[d] = i;
LL b2 = bb * i;
LL a2 = aa * i - bb; //新的分数为 (aa/bb - 1/i) = (aa - bb*i)/(bb*i);
LL g = gcd(a2, b2);
if(dfs(d+1, i+1, a2/g, b2/g))
ok = true;
}
return ok;
}
int main()
{
int ok = 0;
while(scanf("%d %d", &a, &b))
{
for(maxd = 1; ; maxd++)
{
memset(ans, -1, sizeof(ans));
if(dfs(0, get_first(a, b), a, b))
{
ok = 1; break;
}
}
printf("%d/%d = ", a, b);
for(int i = 0; ; i++)
{
if(ans[i] > 0)
printf("%s1/%d", i == 0 ? "" : "+", ans[i]);
else
{printf("\n"); break;}
}
}
return 0;
}