迭代加深,埃及分数

问题描述:

  给出一个分数,由分子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 }

时间: 2024-10-09 03:51:08

迭代加深,埃及分数的相关文章

【迭代加深搜索】埃及分数问题

谢谢阿苏~http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5856756 [迭代加深搜索(ID,iterative deepening)]:从小到大枚举上限maxd,每次执行只考虑深度不超过maxd的结点. ------对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑ID算法: ------优点:它主要是在递归搜索函数的开头判断当前搜索的深度是否大于预定义的最大搜索深度,如果大于,就退出这一层的搜索,如果不大于,就

vijos1308 埃及分数(迭代加深搜索)

题目链接:点击打开链接 题目描述: 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数.如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的.对于一个分数a/b,表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好. 如:19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4 + 1/6

埃及分数问题_迭代加深搜索_C++

一.题目背景 http://codevs.cn/problem/1288/ 给出一个真分数,求用最少的1/a形式的分数表示出这个真分数,在数量相同的情况下保证最小的分数最大,且每个分数不同. 如 19/45=1/3 + 1/12 + 1/180 二.迭代加深搜索 迭代加深搜索可以看做带深度限制的DFS. 首先设置一个搜索深度,然后进行DFS,当目前深度达到限制深度后验证当前方案的合理性,更新答案. 不断调整搜索深度,直到找到最优解. 三.埃及分数具体实现 我们用dep限制搜索层数,先从2开始,每

埃及分数,迭代加深

埃及分数题意非常明白,这里就不解释了…… 但是关于最优解的问题,题目并没有说明 原题: 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好. 然而这并没有考虑一种很恶心的情况:加数一样多,而且最后一个分数一样的时候,哪种情况最优呢? 我先写了个从末尾到开头一位一位判断大小,保证最大的程序,大概只有一半的分数(codevs) 又写了个输出 最先找到的 末尾最大的 方案 的程序,结果90(还是codevs) 我选择放弃,,,

“埃及分数”问题浅谈对迭代加深搜索的理解

迭代加深搜索(IDDFS)的思想 迭代加深搜索一般用来求解状态树"非常深",甚至深度可能趋于无穷,但是"目标状态浅"的问题.如果用普通的DFS去求解,往往效率不够高.此时我们可以对DFS进行一些改进.最直观的一种办法是增加一个搜索的最大深度限制maxd,一般是从1开始.每次搜索都要在maxd深度之内进行,如果没有找到解,就继续增大maxd,直到成功找到解,然后break. 如下图所示,如果用DFS,需要15步才能找到结点3,但是用迭代加深搜索,很快即可找到结点3.

埃及分数问题(迭代加深)

1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 LL tmpans[100000],ans[100000]; 5 int maxd; 6 /** 7 *学习:1.memcpy:复制结构体时加&, 8 数组时不加,数组名即地址 9 2.迭代加深搜索,剪枝条 10 * */ 11 int get_maxb(LL a,LL b){ 12 // 13 //for(int i = 1 ; ; i

Vijos 1308 埃及分数(迭代加深搜索)

题意: 输入a.b, 求a/b 可以由多少个埃及分数组成. 埃及分数是形如1/a , a是自然数的分数. 如2/3 = 1/2 + 1/6, 但埃及分数中不允许有相同的 ,如不可以2/3 = 1/3 + 1/3. 求出可以表达a/b个数最少埃及分数方案, 如果个数相同则选取最小的分数最大. #include <bits/stdc++.h> #define LL long long using namespace std; int maxd; long long v[1234],ans[1234

DFSID:埃及分数

题目描述  Description 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数. 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的. 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好. 如: 19/45=1/3 + 1/12 + 1/180 19/45=1/3 + 1/15 + 1/45 19/45=1/3 + 1/18 + 1/30, 19/45=1/4

1288 埃及分数

1288 埃及分数 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数. 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的. 对于一个分数a/b,表示方法有很多种,但是哪种最好呢? 首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好. 如: 19/45=1/3 + 1/12 + 1/