1. 程式人生 > >叠代加深,埃及分數

叠代加深,埃及分數

col eas 開始 str pen lap i++ mem none

問題描述:

  給出一個分數,由分子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

技術分享
  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 }
View Code

叠代加深,埃及分數