鱼C论坛

 找回密码
 立即注册
查看: 3749|回复: 18

题目23:算出所有不能写成两个过剩数之和的正整数之和

[复制链接]
发表于 2015-4-23 16:30:20 | 显示全部楼层 |阅读模式

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

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

x
Non-abundant sums

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.

题目:

如果一个数的所有真因子之和等于这个数,那么这个数被称为完全数。例如,28 的所有真因子之和为 1 + 2 + 4 + 7 + 14 = 28,所以 28 是一个完全数。

如果一个数的所有真因子之和小于这个数,称其为不足数,如果大于这个数,称其为过剩数。

12 是最小的过剩数,1 + 2 + 3 + 4 + 6 = 16。因此最小的能够写成两个过剩数之和的数字是 24。经过分析,可以证明所有大于 28123 的数字都可以被写成两个过剩数之和。但是这个上界并不能被进一步缩小,即使我们知道最大的不能表示为两个过剩数之和的数字要比这个上界小。

找出所有不能表示为两个过剩数之和的正整数之和。

评分

参与人数 1鱼币 +1 收起 理由
cwhsmile + 1 4179871 用时5.7s

查看全部评分

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

使用道具 举报

发表于 2016-8-27 19:28:57 | 显示全部楼层
  1. def isguoshen(x):
  2.     n = 0
  3.     for i in range(1,x):
  4.         if x%i == 0:
  5.             n += i

  6.     if n > x:
  7.         return True
  8.     else:
  9.         return False

  10. guoshen = []
  11. guoshenhe = {0}

  12. for i in range(12,14062):
  13.     if isguoshen(i):
  14.         guoshen.append(i)

  15. for i in range(3490):
  16.     for j in range(i,3490):
  17.         guoshenhe.add(guoshen[i]+guoshen[j])
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-8-29 22:07:42 | 显示全部楼层
  1. import math

  2. def Full(x):
  3.     list1 = [1]
  4.     for i in range(2,int(math.sqrt(x)+1)):
  5.         if x % i == 0:
  6.             list1.append(i)
  7.             if x/i not in list1:
  8.                 list1.append(x/i)
  9.                
  10.     if sum(list1) > x:
  11.         return True
  12.     else:
  13.         return False      
  14. list1 = []
  15. for i in range(1,28111):
  16.     if Full(i):
  17.         list1.append(i)
  18. list2 = {0}
  19. for i in range(6961):
  20.     for n in range(i,6961):
  21.         list2.add(list1[i]+list1[n])
  22. list3=[]
  23. for i in range(1,28123):
  24.     if i not in list2:
  25.         list3.append(i)

  26. print(sum(list3))
复制代码

结果是4179871,10秒不到出结果
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-9-20 17:18:28 | 显示全部楼层
本帖最后由 jerryxjr1220 于 2016-10-11 23:17 编辑

优化了算法,用标记法,只要2秒多就出结果
  1. 4179871
  2. [Finished in 2.2s]
复制代码

  1. def y(n):
  2.         lst = [1]
  3.         for i in range(2,int(n**0.5+1)):
  4.                 if n%i == 0:
  5.                         lst.append(i)
  6.                         lst.append(int(n//i))
  7.                         lst = list(set(lst))
  8.         return lst

  9. master = [0 for z in range(28124)]
  10. for j in range(1,28124):
  11.         if j == 1:
  12.                 master[j] = 1
  13.         elif j == 2:
  14.                 master[j] = 1
  15.         else:
  16.                 master[j] = sum(y(j))
  17. abundant = []
  18. for k in range(1,28124):
  19.         if k < master[k]:
  20.                 abundant.append(k)
  21. not_abundant = [i for i in range(28124)]
  22. for i, a in enumerate(abundant):
  23.         for b in abundant[i:]:
  24.                 if a+b < 28124:
  25.                         not_abundant[a+b] = 0
  26.                 else:
  27.                         break   # no need to go further
  28. print sum(not_abundant)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-11 22:05:59 | 显示全部楼层
本帖最后由 芒果加黄桃 于 2017-1-11 22:08 编辑
  1. # encoding:utf-8
  2. # 过剩数
  3. from time import time
  4. N = 28123
  5. def getFactorsSum(N):
  6.     l_result = [1]
  7.     for t in range(2, int(N ** 0.5) + 1):
  8.         if N % t == 0:
  9.             l_result.append(t)
  10.             l_result.append(N // t);
  11.     return sum(list(set(l_result)))
  12. def findAbns():
  13.     l_abns = []
  14.     for i in range(1, N):
  15.         if getFactorsSum(i) > i:
  16.             l_abns.append(i)
  17.     return l_abns   
  18. def euler022():
  19.     l_temp = []
  20.     l_abns = findAbns()
  21.     for i in range(0, len(l_abns)):
  22.         for j in range(i, len(l_abns)):
  23.             tmp = l_abns[i] + l_abns[j]
  24.             if tmp > N:
  25.                 break
  26.             l_temp.append(tmp)
  27.     s_abns = set(l_temp)
  28.     s_all = set(i for i in range(1, N + 1))
  29.     l_result = list(s_all - s_abns)
  30.     l_result.sort()
  31.     return l_result
  32.    
  33. if __name__ == '__main__':
  34.     start = time()
  35.     print(sum(euler022()))
  36.     print('cost %.6f sec' % (time() - start))
复制代码

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

使用道具 举报

发表于 2017-1-21 23:43:43 | 显示全部楼层
此代码使用matlab编程
Problem23所用时间为4.2954秒
Problem23的答案为4179871
  1. %% Problem23
  2. % 题目23:算出两个不能够被两个过剩数之和表示的所有正整数之和
  3. function Output=Problem23(Input)
  4. tic
  5. if nargin==0
  6. Input=28123;
  7. end
  8. Abundant=[];
  9. for ii=2:Input
  10.     if sum(Factor_Rank(ii))>ii
  11.         Temp=[Abundant,ii];
  12.         Abundant=Temp;
  13.     end
  14. end
  15. L=length(Abundant);
  16. Result=1:Input;
  17. for jj=1:L
  18.     Result=setdiff(Result,Abundant+Abundant(jj));%巧妙,将2重循环变为单重循环
  19. end
  20. Output=sum(Result);
  21. toc
  22. disp('此代码使用matlab编程')
  23. disp(['Problem23所用时间为',num2str(toc),'秒'])
  24. disp(['Problem23的答案为',num2str(Output)])
  25. end
  26. %% 子程序
  27. %输入一个数,得到其真因子序列,顺序排列,入10,--1,2,5..
  28. function Output=Factor_Rank(Input)
  29. if nargin==0
  30. Input=12;
  31. end
  32. Node=floor(sqrt(Input));
  33. Factor=[];
  34. if Node*Node==Input
  35.     Factor=Node;
  36.     Middle=Node-1;%最中间的约数
  37. else
  38.     Middle=Node;
  39. end
  40. for ii=Middle:-1:2
  41.     if mod(Input,ii)==0
  42.         Temp=[ii,Factor,Input/ii];
  43.         Factor=Temp;
  44.     end
  45. end
  46. Output=[1,Factor];
  47. end


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

使用道具 举报

发表于 2017-3-15 14:55:41 | 显示全部楼层
  1. import time
  2. st = time.clock()
  3. def isabundant(x):
  4.     sum0=1
  5.     for i in range(2,int(x**0.5)+1):
  6.         if not x%i:
  7.             if x==i**2:sum0+=i
  8.             else:sum0+=i+x//i
  9.     if sum0>x:return 1
  10.     else:return 0

  11. l_ab=[]
  12. dic_n={}
  13. for n in range(1,28124):
  14.     if isabundant(n):
  15.         l_ab.append(n)
  16.     dic_n[n]=n
  17. for i in l_ab:
  18.     for j in l_ab:
  19.         if i+j in dic_n:
  20.             del dic_n[i+j]
  21. print(sum(list(dic_n.values())))
  22. et = time.clock()
  23. print('read:%.3f s' %(et-st))
复制代码

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

使用道具 举报

发表于 2018-3-18 18:36:43 | 显示全部楼层
  1. #include<stdio.h>
  2. #include<time.h>
  3. #include<stdlib.h>
  4. int Judeg(int x)
  5. {
  6.         int i,sum=0;
  7.         for(i=1;i<x;i++)
  8.         {
  9.                 if(0==x%i)
  10.                 {
  11.                         sum=sum+i;
  12.                 }       
  13.         }
  14.         if(sum>x)
  15.         {
  16.                 return 1;
  17.         }
  18.         else
  19.         {
  20.                 return 0;
  21.         }
  22. }
  23. int main()
  24. {
  25.         int i,j,n,leap;
  26.         double s=0;
  27.         clock_t start,end;
  28.         start=clock();
  29.         for(n=1;n<=28123;n++)
  30.         {
  31.                 leap=1;
  32.                 for(i=12;i<=n/2;i++)
  33.                 {
  34.                         j=n-i;
  35.                         if(Judeg(i)&&Judeg(j))
  36.                         {
  37.                                 leap=0;
  38.                                 break;
  39.                         }
  40.                 }
  41.                 if(leap)
  42.                 {
  43.                                 s=s+n;
  44.                                 printf("%d\t",n);
  45.                 }
  46.         }
  47.         end=clock();
  48.         printf("\n本次计算用时%f秒\n",(double)(end-start)/CLK_TCK);
  49.         printf("%f\n",s);
  50.         system("pause");
  51.         return 0;
  52. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-22 22:18:55 | 显示全部楼层
from math import sqrt

import time

st = time.time()
def f(n):
    l= set()
    for i in range(1,int(sqrt(n))+1):
        if n % i ==0:
            j = n//i
            l.add(i)
            l.add(j)

    return sum(l-{n})

def g(n):
    if f(n)>n:
        return n
    else:
        return 0

lis  = []
for i in  range(12,28123):
    if g(i) !=0:
        lis.append(g(i))

print(lis)
lis1 = set()
for ii in lis:
    for j in lis:
        lis1.add(ii+j)

lis2 = []
for p in range(1,28123):
    if p not in lis1:
        lis2.append(p)
print(sum(lis2))
print(time.time() - st)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-22 22:19:29 | 显示全部楼层
4179871 9s
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-25 14:37:28 | 显示全部楼层
本帖最后由 k往事如烟k 于 2019-3-25 14:38 编辑

测试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-4-27 01:27:12 | 显示全部楼层
本帖最后由 cwhsmile 于 2019-4-27 12:44 编辑

方法不好,需要优化的地方多,列表对于超过一万以上的长度不建议用,最好用字典,长度低了就用列表。
慢慢的发现,思维方式不同,做出的结果可以差很多倍。
  1. import time
  2. import math

  3. def test1():
  4.     num = []
  5.     for m in range(2,28124):
  6.         li = [1]
  7.         for n in range(2,int(m**0.5)+1):
  8.             if m%n == 0:
  9.                 li.append(n)
  10.                 li.append(int(m/n))

  11.         if sum(set(li)) > m:
  12.             num.append(m)
  13.     long = len(num)
  14.     print(long)
  15.     print(num[-10:])
  16.     b = []
  17.     for n in range(long):
  18.         for i in range(n,long):
  19.             temp = num[i]+num[n]
  20.             if temp < 28124:
  21.                 b.append(temp)
  22.             else:
  23.                 break
  24.    
  25.     print(b[-10:])
  26.     result = 0
  27.     b = set(b)
  28.     print(len(b))
  29.     for j in range(1,28124):
  30.         if j in b:
  31.             continue
  32.         result += j
  33.     return result


  34. li = []
  35. start = time.perf_counter()
  36. print(test1())
  37. end = time.perf_counter()
  38. print(end-start)
复制代码


上面的代码运行了5秒多,下面是改进的代码,把列表换成了字典,把过剩数相加的取值范围缩减了一下,3秒多运行完毕。
  1. import time
  2. import math

  3. def test1():
  4.     num = []
  5.     for m in range(2,28124):
  6.         li = [1]
  7.         for n in range(2,int(m**0.5)+1):
  8.             if m%n == 0:
  9.                 li.append(n)
  10.                 li.append(int(m/n))
  11.         if sum(set(li)) > m:
  12.             num.append(m)
  13.             
  14.     long = len(num)
  15.     dict1 = {}
  16.     for a in range(28124):
  17.         dict1[a] = 1
  18.     for n in range(long//2):
  19.         for i in range(n,long-n):
  20.             temp = num[i]+num[n]
  21.             dict1[temp] = 0

  22.     result = 0
  23.     for j in range(28124):
  24.         if dict1[j] == 1:
  25.             result += j
  26.     return result
  27. li = []
  28. start = time.perf_counter()
  29. print(test1())
  30. end = time.perf_counter()
  31. print(end-start)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2019-6-6 10:54:10 | 显示全部楼层
结果:4179871
用时:5.985732424725128
  1. import time
  2. import math

  3. def guosheng():
  4.     gs_l = []
  5.     for i in range(12, 28123):
  6.         tmp = []
  7.         for x in range(2, int(math.sqrt(i) + 1)):
  8.             if not i % x:
  9.                 tmp.append(x)
  10.                 tmp.append(int(i/x))
  11.         if sum(set(tmp)) > i-1:
  12.             gs_l.append(i)

  13.     return sum(range(28124)) - sum(set([gs_l[n1] + gs_l[n2] for n1 in range(len(gs_l)) for n2 in range(n1, len(gs_l)) if gs_l[n1] + gs_l[n2] < 28124]))


  14. start = time.clock()
  15. print("结果:{}\n用时:{}".format(guosheng(), time.clock()-start))
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-22 21:18:02 | 显示全部楼层
本帖最后由 永恒的蓝色梦想 于 2020-9-11 13:45 编辑

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

使用道具 举报

发表于 2020-8-4 17:13:10 | 显示全部楼层
4179871

Process returned 0 (0x0)   execution time : 0.824 s
Press any key to continue.
暴力打表,先求出1~28123的所有过剩数,再二层循环枚举两过剩数之和
以下为关键代码
  1. const int M = 28123 + 1;
  2. const int M_RANGE = 7000 + 5;

  3. int abundant[M_RANGE];
  4. int vis[M] = {0};

  5. int main(){

  6.   int cnt = 0,ans = 0;
  7.        
  8.   for (int i = 1;i < M;i++){
  9.     int factor_sum = 0;
  10.     for (int j = 1;j <= i/2;j++)
  11.       if (i % j == 0) factor_sum += j;
  12.     if (factor_sum > i) abundant[cnt++] = i;
  13.   }
  14.   
  15.   for (int i = 0;i < cnt;i++)
  16.     for (int j = i;j < cnt;j++){
  17.       int sum = abundant[i] + abundant[j];
  18.       if (sum < M && !vis[sum]) vis[sum] = 1;
  19.   }
  20.   
  21.   for (int i = 0;i < M;i++)
  22.     if (!vis[i]) ans += i;
  23.   
  24.   cout << ans << endl;
  25.         return 0;
  26. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-1-2 20:45:04 | 显示全部楼层
  1. /*
  2. 答案:4179871
  3. 耗时:0.0097935秒
  4. */
  5. #include <iostream>
  6. #include <cmath>
  7. using namespace std;

  8. char a[28124];//打表,a[i]=1表示i是一个过剩数

  9. bool is_abundant(int k)//计算k是否是一个过剩数
  10. {
  11.   int d = (int)sqrt((double)k);
  12.   int s = 1;
  13.   for (int i = 2; i <= d; ++i)
  14.   {
  15.     if (k % i == 0)
  16.     {
  17.       int n = k / i;
  18.       if (i == n)
  19.         s += i;
  20.       else
  21.         s += i + n;
  22.     }
  23.   }
  24.   return (s > k);
  25. }

  26. int main(void)
  27. {
  28.   int nS = 0;
  29.   for (int i = 1; i < 28124; ++i) //打表
  30.   {
  31.     if (is_abundant(i))
  32.       a[i] = 1;
  33.   }
  34.   for (int i = 1; i < 28124; ++i)
  35.   {
  36.     bool bFlg = true;
  37.     for (int j = 1; j <= (i >> 1); ++j) //枚举i的拆分
  38.     {
  39.       if (a[j] == 1 && a[i - j] == 1)
  40.       {
  41.         bFlg = false;
  42.         break;
  43.       }
  44.     }
  45.     if (bFlg)
  46.       nS += i;
  47.   }
  48.   cout << nS << endl;
  49.   return 0;
  50. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-21 11:10:55 | 显示全部楼层
cwhsmile 发表于 2019-4-27 01:27
方法不好,需要优化的地方多,列表对于超过一万以上的长度不建议用,最好用字典,长度低了就用列表。
慢慢 ...

过剩数相加的取值范围缩减了一下,具体有什么原理吗,我感觉好像不能完全覆盖。如果数据很大的话
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-21 11:11:37 | 显示全部楼层
#include<stdio.h>
#include<math.h>

int determine(int i);//求质因数之和
int determine(int i)
{
        int k;
        int sum1=0;
       
        for(k=1;k<=pow(i,1.0/2);k++)
        {
                if(i%k==0&&i/k!=k)
                {
                        sum1=sum1+k+i/k;
                }
                if(i%k==0&&i/k==k)
                {
                        sum1=sum1+k;
                }
        }
        sum1=sum1-i;
        if(sum1>i)
        {
                return sum1;
        }
        else
        {
                return 0;
        }
}

int main(void)
{
        int k=0,i,m;
        long int sum0=0;//前28213的和
        int array[10000]={0};//储存过剩数
        int count=0;//过剩数的数量
        long int sum1=0;
       
        for(i=1;i<=28213;i++)
        {
                sum0=sum0+i;
        }
        printf("%lld\n",sum0);
        for(i=12;i<=28213;i++)
        {
                if(determine(i))
                {
                        array[k]=i;
                        count++;
                        k++;
                }
        }
        printf("%d\n",count);
        for(i=24;i<=28213;i++)
        {
                for(m=0;array[m]<=i;m++)//这里不用<=(i-array[m]),因为我曾经犯过错。除非你赋值
                {
                        if(determine((i-array[m])))
                        {
                                sum1=sum1+i;
                                break;
                        }
                }
        }
       
        printf("%lld\n",sum1);
       
        printf("所有不能表示为两个过剩数之和的正整数之和为%d\n",(sum0-sum1));
       
        return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-10-10 11:46:21 | 显示全部楼层
4179871 0.5s
  1. fn factors(x: i32) -> Vec<i32> {
  2.     let mut pt: Vec<i32> = vec![1];
  3.     let mut x_sq = (x as f32).sqrt() as i32;
  4.     if x == x_sq * x_sq && x > 1 {
  5.         pt.push(x_sq);
  6.         x_sq -= 1;
  7.     }
  8.     for i in 2..=x_sq {
  9.         if x % i == 0 {
  10.             pt.push(i);
  11.             pt.push(x / i);
  12.         }
  13.     }
  14.     pt
  15. }

  16. fn main() {
  17.     let mut abundant = Vec::new();
  18.     for i in 1..=28123 {
  19.         if factors(i).iter().sum::<i32>() > i {
  20.             abundant.push(i);
  21.         }
  22.     }
  23.     let mut number_table: Vec<bool> = vec![true; 28124];
  24.     for i in &abundant {
  25.         for j in &abundant {
  26.             if i + j < 28124 {
  27.                 number_table[(i + j) as usize] = false;
  28.             }
  29.         }
  30.     }
  31.     println!(
  32.         "{}",
  33.         number_table
  34.             .iter()
  35.             .enumerate()
  36.             .map(|(i, &x)| if x { i as i32 } else { 0 })
  37.             .sum::<i32>()
  38.     )
  39. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-25 12:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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