找回密码
 欢迎注册
楼主: 无心人

[讨论] 埃及分数问题

[复制链接]
发表于 2008-3-7 13:01:44 | 显示全部楼层
记忆中好像有人发过很类似的ACM题目,不过感觉这种题目基本上就是靠搜索(技巧就在于如何更好的缩小搜索范围) 无心人发的这三个题目中应该这个最复杂
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 13:43:25 | 显示全部楼层
报个到先,准备写个程序。 如果想搞个比赛的话,可以这样,大家可以将你的程序打包并加密码,并以附件形式贴出。到了约定期限,告知密码,这样大家就可以拿到程序并测评。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-7 13:55:05 | 显示全部楼层
不要忒复杂了 想到代码你就发 这个题目要求技巧高些而已 还有输出多点 应该超过10万吧 :)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 16:09:11 | 显示全部楼层
搜索 8个分数(7115组解), 就需要 不少时间,如果指定16个分数,时间太长了。下面是我的源代码,如果需要搜索到16个,请修改 全局变量 max_level的值为16.
  1. #include "stdafx.h"
  2. #include "math.h"
  3. int maxN=256;
  4. double maxN_r= 1/256.00;
  5. int max_level=8; //共有7115组解
  6. //int max_level=16;
  7. int count=0;
  8. void printfArr(int arr[],int len)
  9. {
  10. for (int i=0;i<len-1;i++)
  11. {
  12. printf("1/%d +",arr[i]);
  13. }
  14. printf("1/%d =1\n",arr[len-1]);
  15. }
  16. bool check(int arr[],int len)
  17. {
  18. int n=arr[len-1];
  19. bool ret=true;
  20. for (int i=0;i<len-1;i++)
  21. {
  22. if (n % arr[i] !=0)
  23. {
  24. ret=false;
  25. break;
  26. }
  27. }
  28. return ret;
  29. }
  30. void search(int arr[], int level, double rem)
  31. {
  32. int i;
  33. double newRem;
  34. if (level==0)
  35. {
  36. for (i=2;i<=maxN;i++)
  37. {
  38. arr[level]=i;
  39. newRem= 1- 1.0 /(double)i;
  40. search(arr,level+1,newRem);
  41. }
  42. }
  43. else if (level<max_level-1)
  44. {
  45. if ( rem * arr[level-1] - 1e-12 > max_level-level)
  46. {
  47. return;
  48. }
  49. else if ( rem * maxN + 1e-12 < 1)
  50. {
  51. return;
  52. }
  53. int from= (int)(ceil(1.0/rem));
  54. if ( from<arr[level-1])
  55. from =arr[level-1];
  56. for (i=from;i<=maxN;i++)
  57. {
  58. arr[level]=i;
  59. newRem= rem - 1.0 /(double)i;
  60. search(arr,level+1,newRem);
  61. }
  62. }
  63. else if (level==max_level-1) //level+1个数
  64. {
  65. int from= (int)(ceil(1.0/rem));
  66. if ( from<=maxN && from>=arr[level-1] && fabs( 1/(double)from - rem) <1e-15 )
  67. {
  68. arr[level]= from;
  69. if ( check( arr, max_level) )
  70. {
  71. count++;
  72. printfArr(arr,level+1);
  73. }
  74. }
  75. }
  76. }
  77. int main(int argc, char* argv[])
  78. {
  79. int arr[16];
  80. count=0;
  81. search(arr,0,1.0);
  82. printf("总共 %d 组解\n",count);
  83. return 0;
  84. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 16:29:37 | 显示全部楼层
有想到一种更快的算法,假定其中的某一组解是 1/N1 + 1/N2 + 1/N16=1 2<= N1 <= N2.. N15 < = N16 我们只需关注N16即可, N16 一定大于等于16,且小于等于256, 对每个可能的N16,我们求其所有约数,如果约束个数小于16,则不予考虑。如果N16的约数个数大于等于16,则 求出N16 的所有约数,若他的所有约数的集合为S,我们只需要从这个结合S中去取数,并搜索即可。这样由于数的集合大为缩小,搜索速度也快的多。 1-256中,240的约数做多,有20个。因此,在最坏情况下,需搜索的数从 255个降到20个。有望迅速解出。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 16:53:02 | 显示全部楼层

回复 14# 的帖子

不知先建一个倒数表是否可加速?一点小建议。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 17:08:07 | 显示全部楼层
原帖由 无心人 于 2008-3-7 13:55 发表 不要忒复杂了 想到代码你就发 这个题目要求技巧高些而已 还有输出多点 应该超过10万吧 :)
我估计会远远超过10万的,记得以前做的2-100,选10个,就6万多了。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 17:37:41 | 显示全部楼层
原帖由 liangbch 于 2008-3-7 16:29 发表 有想到一种更快的算法,假定其中的某一组解是 1/N1 + 1/N2 + 1/N16=1 2
这种方法只能找出部分解,不能找到所有解。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 17:38:27 | 显示全部楼层
原帖由 gxqcn 于 2008-3-7 16:53 发表 不知先建一个倒数表是否可加速?一点小建议。
这种方法可以提高速度一些,但是不会有明显的改善,这种优化应该在最后才考虑。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-7 17:40:28 | 显示全部楼层
按照上面的思路,重写编写程序,15秒可解除 4220074组解(不打出每组解)。 to 18#, 能否举个反例? 代码如下:
  1. #include "stdafx.h"
  2. #include "math.h"
  3. int maxN=256;
  4. double maxN_r= 1/256.00;
  5. int max_level=16; //共有7115组解
  6. //int max_level=16;
  7. int count=0;
  8. void printfArr(int arr[],int len)
  9. {
  10. #ifdef _DEBUG
  11. for (int i=0;i<len-1;i++)
  12. {
  13. printf("1/%d +",arr[i]);
  14. }
  15. printf("1/%d =1\n",arr[len-1]);
  16. #endif
  17. }
  18. bool check(int arr[],int len)
  19. {
  20. int n=arr[len-1];
  21. bool ret=true;
  22. for (int i=0;i<len-1;i++)
  23. {
  24. if (n % arr[i] !=0)
  25. {
  26. ret=false;
  27. break;
  28. }
  29. }
  30. return ret;
  31. }
  32. void search(int arr[], int level, double rem)
  33. {
  34. int i;
  35. double newRem;
  36. if (level==0)
  37. {
  38. for (i=2;i<=maxN;i++)
  39. {
  40. arr[level]=i;
  41. newRem= 1- 1.0 /(double)i;
  42. search(arr,level+1,newRem);
  43. }
  44. }
  45. else if (level<max_level-1)
  46. {
  47. if ( rem * arr[level-1] - 1e-12 > max_level-level)
  48. {
  49. return;
  50. }
  51. else if ( rem * maxN + 1e-12 < 1)
  52. {
  53. return;
  54. }
  55. int from= (int)(ceil(1.0/rem));
  56. if ( from<arr[level-1])
  57. from =arr[level-1];
  58. for (i=from;i<=maxN;i++)
  59. {
  60. arr[level]=i;
  61. newRem= rem - 1.0 /(double)i;
  62. search(arr,level+1,newRem);
  63. }
  64. }
  65. else if (level==max_level-1) //level+1个数
  66. {
  67. int from= (int)(ceil(1.0/rem));
  68. if ( from<=maxN && from>=arr[level-1] && fabs( 1/(double)from - rem) <1e-15 )
  69. {
  70. arr[level]= from;
  71. if ( check( arr, max_level) )
  72. {
  73. count++;
  74. printfArr(arr,level+1);
  75. }
  76. }
  77. }
  78. }
  79. bool check2(int arr[],int len)
  80. {
  81. int n=arr[len-1];
  82. int s=0;
  83. for (int i=0;i<len;i++)
  84. {
  85. s+= n / arr[i];
  86. }
  87. return (s==n);
  88. }
  89. void search2(int fac[], int facLen, int arr[], int level, double rem,int lastIdx,int n)
  90. {
  91. int i;
  92. double newRem;
  93. if (level==0)
  94. {
  95. for (i=0;i<facLen;i++)
  96. {
  97. arr[level]=fac[i];
  98. newRem= 1- 1.0 /(double)(fac[i]);
  99. search2(fac,facLen,arr,level+1,newRem,i,n);
  100. }
  101. }
  102. else if (level<max_level-1)
  103. {
  104. if ( rem * arr[level-1] - 1e-12 > max_level-level)
  105. {
  106. return;
  107. }
  108. else if ( rem * fac[facLen-1] + 1e-12 < 1)
  109. {
  110. return;
  111. }
  112. for (i=lastIdx;i< facLen;i++)
  113. {
  114. arr[level]=fac[i];
  115. newRem= rem - 1.0 /(double)(fac[i]);
  116. search2(fac,facLen,arr,level+1,newRem,i,n);
  117. }
  118. }
  119. else if (level== max_level-1)
  120. {
  121. arr[level]=n;
  122. level++;
  123. rem-= 1.0/(double)n;
  124. if ( check2( arr, level) && fabs(rem)<1e-15 )
  125. {
  126. count++;
  127. printfArr(arr,level);
  128. }
  129. }
  130. }
  131. int getFacNums(int n, int arr[])
  132. {
  133. int c=0;
  134. for (int i=2;i<=n; i++)
  135. {
  136. if (n % i==0)
  137. {
  138. arr[c]=i;
  139. c++;
  140. }
  141. }
  142. return c;
  143. }
  144. void test2()
  145. {
  146. int i;
  147. int fac[256];
  148. int arr[16];
  149. int c;
  150. for (i=max_level;i<=256;i++)
  151. {
  152. c= getFacNums(i,fac);
  153. search2(fac, c, arr, 0, 1.0, 0,i);
  154. }
  155. }
  156. int main(int argc, char* argv[])
  157. {
  158. int arr[16];
  159. count=0;
  160. //search(arr,0,1.0);
  161. test2();
  162. printf("总共 %d 组解\n",count);
  163. return 0;
  164. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-23 16:13 , Processed in 0.029656 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表