问题描述:
给出一个分数,由分子a 和分母b 构成,现在要你分解成一系列互不相同的单位分数(形如:1/a,即分子为1),要求:分解成的单位分数数量越少越好,如果数量一样,最小的那个单位分数越大越好。
如:
19/45 = 1/3 + 1/12 + 1/180;
19/45 = 1/5 + 1/6 + 1/18;
由于,1/18比1/180更大,所以第二种情况更优。
59/211=1/4 + 1/36 + 1/633 + 1/3798
59/211=1/6 + 1/9 + 1/633 + 1/3798
同样,第二种情况更优。
解题思路:
(1)枚举深度maxd (从1开始)
(2)dfs搜索:从满足1/c<=a/b的最小c即b/a+1开始枚举分母,深度d(从0开始)为表示第几个分数;每次计算的是a/b - 1/i = a2/b2 然后将a2,b2再作为a,b进行递归,同时传入,下一个分母的可能最小值。
(3)剪枝:if(bb * (maxd-d) <= i*aa) break;//剪枝:如果剩下的maxd+1-d个分数全部都是1/i,加起来仍然不超过aa/bb,则无解! (maxd-d)/i <= aa/bb
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 //埃及分数 2 3 #include<iostream> 4 #include<algorithm> 5 6 using namespace std; 7 #define M 20 //加数项的最大个数 8 9 int MaxD; //每次迭代加深时的深度 10 bool flag ; //当前深度下是否有解的标志 11 int v[M], ans[M]; //v数组记录过程中的分母,ans记录最优分母 12 13 int gcd(int a, int b) //求最大公约数 14 { 15 int sum = 0; 16 while (a) 17 { 18 sum = b%a; 19 b = a; 20 a = sum; 21 } 22 return b; 23 } 24 25 void better() //求最优值 26 { 27 for (int i = MaxD-1; i >= 0; i--) //i 表示下标 28 { 29 if (ans[i] == 0) //第一个满足条件的 30 { 31 for (int j = 0; j < MaxD; j++) 32 { 33 ans[j] = v[j]; 34 } 35 flag = true; 36 break; 37 } 38 else if (v[i] > ans[i]) 39 { 40 break; 41 } 42 else if (v[i] < ans[i]) //其他满足条件的情况 43 { 44 for (int j = 0; j < MaxD; j++) 45 { 46 ans[j] = v[j]; 47 } 48 flag = true; 49 break; 50 } 51 } 52 } 53 54 bool dfs(int a, int b, int dep,int MC) 55 { 56 int c = 1; 57 int aa = 1, bb = 1; 58 int s = gcd(a, b); 59 if (dep >= MaxD) 60 { 61 return flag; 62 } 63 else 64 { 65 a = a / s; 66 b = b / s; 67 if (a == 1) 68 {//存在结果的出口,进行回溯 69 v[dep] = b; 70 better(); //搜索到解的时候,肯定是到达了MaxD层 71 return flag; 72 } 73 else 74 { 75 c = max(b / a + 1, MC); 76 for ( ;; c++) 77 { 78 if (b*(MaxD - dep) <= c*a) //当前深度下,后续分母最大值不能使等式成立 79 { 80 break; 81 } 82 v[dep] = c; 83 aa = a*c - b; 84 bb = b*c; 85 dfs(aa, bb, dep + 1,c+1); //保证后一项的分母比前一项小 86 } 87 return flag; 88 } 89 } 90 } 91 92 int main() 93 { 94 int a, b; 95 while (cin >> a >> b) 96 { 97 memset(v, 0, sizeof(v)); 98 memset(ans, 0, sizeof(ans)); 99 flag = false; 100 //判断a,b合法性; 101 if (a > b || a*b == 0) 102 { 103 cout << "please enter the legal numbers!" << endl; 104 continue; 105 } 106 else 107 { 108 for (MaxD = 1;; MaxD++) 109 if (dfs(a,b,0,1)) //存在结果则停止迭代搜索,跳出循环 110 break; 111 } 112 //输出不等式 113 cout << a << "/" << b << "="; 114 for (int i = 0; i < MaxD-1; i++) //退出循环,MaxD没有改变 115 { 116 cout << 1 << "/" << ans[i] << "+"; 117 } 118 cout << 1 << "/" << ans[MaxD - 1] << endl << endl; //最后一个项 119 } 120 }