埃及分数问题,在古埃及人们使用单位分数的和来表示一切有理数。例如2/3 = 1/2 + 1/6,但不允许使用2/3=1/3+1/3,因为在加法数中不允许重复。
对于一个分数a/b,表示方法有多种,其中加数少的比加数多的好,如果加数个数相同,则最小的分数越大越好。
解决方案是采用迭代加深搜索:从小到大枚举上限maxed.每次执行只考虑深度不超过maxed的点。这样只要解的深度有限就可以在有限时间内枚举到.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int ans[105], vis[105], maxed;
ll gcd(ll a, ll b){
return b ? gcd(b, a % b) : a;
}
ll get_first(ll a, ll b){
ll c = b / a;
if(b % a)
c++;
return c;
}
bool better(int d){
for(int i = d; i >= 1; i--){
if(vis[i] != ans[i]){
return ans[i] == 0 || vis[i] < ans[i];
}
}
return false;
}
bool dfs(int d, int from, ll a, ll b){
if(d == maxed){
if(b % a)
return false;
vis[d] = b / a;
if(better(d)){
memcpy(ans, vis, sizeof(vis));
}
return true;
}
bool ok = false;
from = max((ll)from, get_first(a, b));
for(int i = from;; i++){
if(b * (maxed - d + 1) <= i * a)
break;
vis[d] = i;
ll b2 = b * i;
ll a2 = a * i - b;
ll k = gcd(a2, b2);
if(dfs(d+1, i+1, a2/k, b2/k))
ok = true;
}
return ok;
}
int main(){
// freopen("in.txt", "r", stdin);
ll a, b;
scanf("%I64d%I64d", &a, &b);
for(maxed = 1;; maxed++){
if(dfs(1, get_first(a, b), a, b)){
break;
}
}
printf("%I64d/%I64d = 1/%d", a, b, ans[1]);
for(int i = 2; i <= maxed; i++)
printf("+ 1/%d", ans[i]);
return 0;
}