鱼C论坛

 找回密码
 立即注册
查看: 2742|回复: 16

题目71:将最简真分数按照升序排列

[复制链接]
发表于 2015-11-5 16:21:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Ordered fractions

Consider the fraction, n/d, where n and d are positive integers. If n<d and HCF(n,d)=1, it is called a reduced proper fraction.

If we list the set of reduced proper fractions for d ≤ 8 in ascending order of size, we get:

1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

It can be seen that 2/5 is the fraction immediately to the left of 3/7.

By listing the set of reduced proper fractions for d ≤ 1,000,000 in ascending order of size, find the numerator of the fraction immediately to the left of 3/7.

题目:

考虑分数 n/d, 其中 n 和 d 是正整数。如果 n<d 并且最大公约数 HCF(n,d)=1, 它被称作一个最简真分数。

如果我们将 d ≤ 8 的最简真分数按照大小的升序列出来,我们得到:

1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

可以看出 2/5 是 3/7 左边的第一个分数。

如果将 d ≤ 1,000,000 的真分数按照大小升序列出,3/7 左边第一个分数的分子是多少?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-9-25 03:31:40 | 显示全部楼层
本帖最后由 jerryxjr1220 于 2017-10-12 10:42 编辑
  1. i=428570, j=999997
  2. [Finished in 0.1s]

  3. most, mosti, mostj = 0,0,0

  4. for j in range(1,1000001):
  5.     i = j*3//7
  6.     if i/j < 3/7:
  7.         if most < i/j:
  8.             most = i/j
  9.             mosti = i
  10.             mostj = j
  11. print (f'i={mosti},j={mostj}')
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-5 21:30:46 | 显示全部楼层
  1. from fractions import Fraction
  2. import math
  3. def Prime(x):
  4.     if x>1:
  5.         if x==2:
  6.             return True
  7.         if x%2==0:
  8.             return False
  9.         for i in range(3,int(math.sqrt(x)+1),2):
  10.             if x%i==0:
  11.                 return False
  12.         return True
  13.     return False
  14. def Dig(x):
  15.     list1=[]
  16.     if Prime(x):
  17.         list1.append(x)
  18.     else:
  19.         for i in range(2,int(math.sqrt(x)+1)):
  20.             if x%i == 0:
  21.                 list1.extend([i,int(x/i)])
  22.     return list1
  23. def Hcf(x,y):
  24.     if x!=y:
  25.         if x==1:
  26.             return True
  27.         for each in Dig(y):
  28.             if x%each == 0:
  29.                 return False
  30.         return True
  31.    
  32. list2 = [Fraction(1,7),Fraction(2,7),Fraction(3,8)]
  33. for i in range(4,428571):
  34.     y = int(7*i/3)+1
  35.     while True:
  36.         if Hcf(i,y):
  37.             list2.append(Fraction(i,y))
  38.             break
  39.         else:
  40.             y += 1
  41. list2.sort()
  42. print(list2[-1])
复制代码

结果:428570/999997
答案是428570
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-5 21:31:45 | 显示全部楼层
一如既往得慢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-24 16:30:05 | 显示全部楼层
  1. # encoding:utf-8
  2. # 最接近3/7的真分数   分母<1000000
  3. from time import time
  4. from math import sqrt
  5. def getPrimes(n):
  6.     primes = [True] * n
  7.     primes[0], primes[1] = False, False
  8.     for (i, prime) in enumerate(primes):
  9.         if prime:
  10.             for j in range(i * i, n, i):
  11.                 primes[j] = False
  12.     return [k for (k, v) in enumerate(primes) if v]
  13. def findPrimeFactors(n, l_pr, s_pr):
  14.     if n in s_pr:
  15.         return [n]
  16.     sqr_n = int(sqrt(n))
  17.     result = list()
  18.     for pr in l_pr:
  19.         if n % pr == 0:
  20.             result.append(pr)
  21.             result.extend(findPrimeFactors(int(n / pr), l_pr, s_pr))
  22.             break
  23.         if pr > sqr_n:
  24.             break
  25.     return result
  26. def euler071(N=1000000):
  27.     l_primes = getPrimes(N)
  28.     s_pr = set(l_primes)
  29.     l_pr = [x for x in l_primes if x <= int(sqrt(N)) + 1]
  30.     maxfz, maxfm = int(3 / 7 * N), N
  31.     maxrt, a, b = 0, 0, 0
  32.     for i in range(maxfz, 2, -1):
  33.         for j in range(int(i * 7 / 3), maxfm):
  34.             t = i / j
  35.             if t < 3 / 7 :  # 满足题目条件
  36.                 if t > maxrt:  # 比已找到的更接近3/7
  37.                     s_i = set(findPrimeFactors(i, l_pr, s_pr))
  38.                     s_j = set(findPrimeFactors(j, l_pr, s_pr))
  39.                     if not(s_i & s_j):  # 没有公共的质数因子
  40.                         maxrt, a, b = t, i, j  
  41.                 else:
  42.                     break         
  43.     print(maxrt, a, b)
  44. if __name__ == '__main__':
  45.     start = time()
  46.     euler071()
  47.     print('cost %.6f sec' % (time() - start))
复制代码

0.42857128571385716 428570 999997
cost 1.133000 sec
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-10-3 21:58:11 | 显示全部楼层
改写了一下,用的matlab,
成功解决
结果是
      428570      999997

时间已过 0.053004 秒。
>>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-8-4 09:47:11 | 显示全部楼层
本帖最后由 永恒的蓝色梦想 于 2021-1-31 14:55 编辑
  1. min_difference = 1
  2. min_numerator = 0
  3. three_div_seven = 3 / 7


  4. for denominator in range(1000000, 0, -1):
  5.     numerator = 3 * denominator // 7
  6.     difference = three_div_seven - numerator / denominator

  7.     if difference and difference < min_difference:
  8.         min_difference = difference
  9.         min_numerator = numerator


  10. print(min_numerator)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-29 18:33:29 | 显示全部楼层
428570

Process returned 0 (0x0)   execution time : 649.486 s
Press any key to continue.
效率极低……求指点
  1. #include<algorithm>
  2. #include<iostream>
  3. #include<set>
  4. using namespace std;

  5. const int M = 1e5;
  6. const double ub = 3.0/7;
  7. int ct = 0;
  8. bool prime[M];
  9. int factor[M];
  10. set<int> fac_n;

  11. void euler_sieve(){
  12.   prime[1] = false;
  13.   for (int i = 2;i <= M;i++) prime[i] = true;

  14.   for (int i = 2;i <= M;i++){
  15.     if (prime[i]) factor[++ct] = i;
  16.     for (int j = 1;j <= ct && i*factor[j] < M;j++){
  17.       prime[i*factor[j]] = false;
  18.       if (i % factor[j] == 0) break;
  19.     }
  20.   }
  21. }

  22. bool co_prime(int x,int y){//x < y
  23.   if (x == 1) return true;
  24.   if (prime[y]) return true;
  25.   if (prime[x] && y % x)  return true;
  26.   if (y == x*2 + 1) return true;

  27.   for (set<int>::iterator it = fac_n.begin();it != fac_n.end();++it){
  28.     if (y % *it == 0) return false;
  29.   }
  30.   return true;
  31. }

  32. void parse(int x,set<int> & s){
  33.   for (int i = 1;x != 1;i++){
  34.     int t = factor[i];
  35.     while(x % t == 0) {s.insert(t); x /= t;}
  36.   }
  37. }

  38. int main(){
  39.   double lb = 1.0/3;
  40.   int ans;
  41.   euler_sieve();

  42.   for (int d = 4;d <= M;d++){
  43.     for (int n = 1;n < (d+1)/2;n++){
  44.       double t = (double)n / d;
  45.       if (lb < t && t < ub){
  46.         fac_n.clear();
  47.         parse(n,fac_n);
  48.         if (co_prime(n,d) )  {lb = t; ans = n;}
  49.       }
  50.     }
  51.   }
  52.   cout << ans << endl;
  53.   return 0;
  54. }
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +5 收起 理由
永恒的蓝色梦想 + 5 + 5 + 5

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-30 10:38:38 | 显示全部楼层
本帖最后由 永恒的蓝色梦想 于 2020-8-30 19:05 编辑
  1. #include<iostream>
  2. using namespace std;



  3. int main() {
  4.     ios::sync_with_stdio(false);

  5.     long double min_difference = 1, difference;
  6.     unsigned long long denominator, result = 0, numerator;


  7.     for (denominator = 1; denominator <= 1000000; denominator++) {
  8.         numerator = 3 * denominator / 7;
  9.         difference = 3.0L / 7 - (long double)numerator / denominator;

  10.         if (difference && difference < min_difference) {
  11.             min_difference = difference;
  12.             result = numerator;
  13.         }
  14.     }


  15.     cout << result << endl;
  16.     return 0;
  17. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-30 11:01:29 | 显示全部楼层
debuggerzh 发表于 2020-8-29 18:33
428570

Process returned 0 (0x0)   execution time : 649.486 s

第6行应该是1e6,调试忘记改了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-30 11:26:50 | 显示全部楼层

感谢大神的思路!以下是改进版本:
428570

Process returned 0 (0x0)   execution time : 0.248 s
Press any key to continue.
只枚举分母,计算最接近结果的分子,大大减少循环次数
  1. #include<algorithm>
  2. #include<iostream>
  3. #include<set>
  4. using namespace std;

  5. const int M = 1e6;
  6. const double ub = 3.0/7;
  7. int ct = 0;
  8. bool prime[M];
  9. int factor[M];
  10. set<int> fac_n;

  11. void euler_sieve(){
  12.   prime[1] = false;
  13.   for (int i = 2;i <= M;i++) prime[i] = true;

  14.   for (int i = 2;i <= M;i++){
  15.     if (prime[i]) factor[++ct] = i;
  16.     for (int j = 1;j <= ct && i*factor[j] < M;j++){
  17.       prime[i*factor[j]] = false;
  18.       if (i % factor[j] == 0) break;
  19.     }
  20.   }
  21. }

  22. bool co_prime(int x,int y){//x < y
  23.   if (x == 1) return true;
  24.   if (prime[y]) return true;
  25.   if (prime[x] && y % x)  return true;
  26.   if (y == x*2 + 1) return true;

  27.   for (set<int>::iterator it = fac_n.begin();it != fac_n.end();++it){
  28.     if (y % *it == 0) return false;
  29.   }
  30.   return true;
  31. }

  32. void parse(int x,set<int> & s){
  33.   for (int i = 1; ;i++){
  34.     int t = factor[i];
  35.     while(x % t == 0) {s.insert(t); x /= t;}
  36.     if (x == 1 || prime[x]) break;
  37.   }
  38.   if (prime[x]) s.insert(x);
  39. }

  40. int main(){
  41.   double lb = 1.0/3;
  42.   int ans;
  43.   euler_sieve();

  44.   for (int d = 4;d <= M;d++){
  45.     int n = (int)(d*3 - 1) / 7;
  46.       double t = (double)n / d;
  47.       if (lb < t && t < ub){
  48.         fac_n.clear();
  49.         parse(n,fac_n);
  50.         if (co_prime(n,d) )  {lb = t; ans = n;}
  51.       }
  52.   }
  53.   cout << ans << endl;
  54.   return 0;
  55. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-30 11:31:29 | 显示全部楼层
本帖最后由 永恒的蓝色梦想 于 2020-8-30 11:39 编辑
debuggerzh 发表于 2020-8-30 11:26
感谢大神的思路!以下是改进版本:
428570


并不需要判断质数。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-3-21 12:11:55 | 显示全部楼层
本帖最后由 guosl 于 2022-1-11 19:52 编辑
  1. /*
  2. 428570
  3. 0.161768
  4. */
  5. #include <iostream>
  6. #include <algorithm>
  7. using namespace std;

  8. int main(void)
  9. {
  10.   int n = 0, d = 1;
  11.   for (int i = 2; i <= 1000000; ++i)
  12.   {
  13.     for (int j = (3 * i + 6) / 7; 999 * j >= 428 * i; --j)
  14.     {
  15.       if (7 * j >= 3 * i)
  16.         continue;
  17.       if (n*i < j*d)
  18.       {
  19.         n = j;
  20.         d = i;
  21.       }
  22.     }
  23.   }
  24.   cout << n << endl;
  25.   return 0;
  26. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-1-11 20:53:01 | 显示全部楼层
本帖最后由 guosl 于 2022-1-12 08:20 编辑

这道题我们先从数学上来讨论一下:对m<n的真分数,我们有以下事实:
1. m/n>m/(n+1)
2. m/n>(m-1)/n
3. m/n>(m-1)/(n-1)
4. m/(n+1) > (m-1)/n , m/(n+1) > (m-1)/(n-1) ,(m-1)/(n-1)>(m-1)/n。总结就是: m/n>m/(n+1) > (m-1)/(n-1)>(m-1)/n,当m/n=3/7时。
在本题中3/7=428571/999999,那么我们可以通过分母加1,分子减1,或分子与分母同时减1,或分子分母同时加1来调整与3/7的距离。但这些调整都预示着分子就在428571的附件,分母就在999999的附近。
为了省却调整的不确定性,我们干脆就在分母d是999990~1000000之间枚举,而分子就是428560~3*d/7之间枚举。
  1. /*
  2. 答案:428570
  3. */
  4. #include <iostream>
  5. using namespace std;

  6. int gcd(int x, int y)
  7. {
  8.   if (y == 0)
  9.     return x;
  10.   int z = x % y;
  11.   while (z != 0)
  12.   {
  13.     x = y;
  14.     y = z;
  15.     z = x % y;
  16.   }
  17.   return y;
  18. }

  19. int main(void)
  20. {
  21.   int n0 = 0, d0 = 1;
  22.   for (int d = 999990; d <= 1000000; ++d)
  23.   {
  24.     for (int n = 428560; 7 * n < 3 * d; ++n)
  25.     {
  26.       long long l1 = n0, l2 = d0;
  27.       l1 *= d;
  28.       l2 *= n;
  29.       if (l1 < l2)
  30.       {
  31.         n0 = n;
  32.         d0 = d;
  33.       }
  34.     }
  35.   }
  36.   cout << n0 / gcd(n0, d0) << endl;
  37.   return 0;
  38. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-28 18:51:19 | 显示全部楼层
应该是测不到时间,毕竟连循环都没有
  1. # 3/7约等于m/n
  2. # 3n-7m=1 ==> 3/7=(m+1/7)/n
  3. # 3n=7m+1 ==> 3n%7=1
  4. # n%7=5
  5. d=1000000
  6. n=d//7*7+5
  7. if n>d:
  8.     n=n-7
  9. m=(3*n-1)//7
  10. print(m)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2024-1-3 19:37:31 | 显示全部楼层
本题等效于寻找n/m,使得3/7-n/m最小
3/7-n/m=(3m-7n)/7m
使得分子=1,m尽可能大即可
时间:<0.001ms
  1. int test71 (int n)
  2. {
  3.     for (int i = n; i >0; i--)
  4.     {
  5.         if(i * 3% 7==1)
  6.         return i * 3/ 7;
  7.     }
  8. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-23 21:33:15 | 显示全部楼层
  1. if __name__ == '__main__':
  2.     import datetime, time

  3.     print(datetime.datetime.now().strftime('%F %T'))
  4.     start = time.time()
  5.     N = 1000000
  6.     m = (N - 5) // 7
  7.     print(f'Problem 71 : {m * 3 + 2}, {m * 7 + 5}')
  8.     print("用时 %.6f 秒" % (time.time() - start))

  9. 2024-04-23 21:32:18
  10. Problem 71 : 428570, 999997
  11. 用时 0.000000 秒
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-24 10:07

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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