Quantcast
Channel: 円周率近似値の日に生まれて理系じゃないわけないだろ! - knifeのblog
Viewing all articles
Browse latest Browse all 5376

社交数の組を列挙するプログラム

$
0
0

午後のひとときに、プログラミングの問題を考えてみる。

社交数とは、
ある自然数AのAを除いた約数の和がB、
BのBを除いた約数の和がC、
CのCを除いた約数の和がAとなる
(A,B,C)のような3個組以上の組である。

問題
社交数の組をAを昇順で列挙するプログラムを組め。


シンキングタ~イム


前回の友愛数のプログラムを改変しましょう。

yuaisu.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    unsigned long long c, p, q, r, i, j, k, t, s;
    int a[42325] = {/* カット */},n;

    if ( argc == 3 ) {
        c = atoll(argv[1]);
        p = atoll(argv[2]);
    } else {
        c = 0;
        p = 2;
    }
    for (; p<=ULONG_LONG_MAX/10; p++) {
        printf("%llu\r",p);
        t = p;
        s = sqrtl(t);
        q = 1;
        i = 2;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 3;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 5;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 7;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 11;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 13;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        i = 17;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        q *= k;
        for (i=19,n=0; i<=s; i+=a[n],n=(n+1)%42325) {
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            q *= k;
        }
        if ( t > 1 ) {
            q *= 1+t;
        }
        q -= p;
        if ( p >= q ) continue;
        t = q;
        s = sqrtl(t);
        r = 1;
        i = 2;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 3;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 5;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 7;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 11;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 13;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        i = 17;
        j = i;
        k = 1;
        while ( t%i == 0 ) {
            k += j;
            t /= i;
            j *= i;
        }
        r *= k;
        for (i=19,n=0; i<=s; i+=a[n],n=(n+1)%42325) {
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            r *= k;
        }
        if ( t > 1 ) {
            r *= 1+t;
        }
        r -= q;
        if ( p == r ) {
            c++;
            printf("%llu: (%llu,%llu)\n",c,p,q);
        }        
    }

    return EXIT_SUCCESS;
}

これのp、q、rを1つの配列でまとめます。

shakosu.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    unsigned long long c, p[30], i, j, k, t, s;
    int a[42325] = {/* カット */},n;

    if ( argc == 3 ) {
        c = atoll(argv[1]);
        p[0] = atoll(argv[2]);
    } else {
        c = 0;
        p[0] = 2;
    }
    for (; p[0]<=ULONG_LONG_MAX/10; p[0]++) {
        printf("%llu\r",p[0]);
        t = p[0];
        s = sqrtl(t);
        m = 0;
        do {
            m++;
            p[m] = 1;
            i = 2;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 3;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 5;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 7;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 11;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 13;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            i = 17;
            j = i;
            k = 1;
            while ( t%i == 0 ) {
                k += j;
                t /= i;
                j *= i;
            }
            p[m] *= k;
            for (i=19,n=0; i<=s; i+=a[n],n=(n+1)%42325) {
                j = i;
                k = 1;
                while ( t%i == 0 ) {
                    k += j;
                    t /= i;
                    j *= i;
                }
                p[m] *= k;
            }
            if ( t > 1 ) {
                p[m] *= 1+t;
            }
            p[m] -= p[m-1];
            t = p[m];
        } while ( m < 30 && p[0] < p[m] );
        if ( m > 2 && p[0] == p[m] ) {
            c++;
            printf("%llu: %d: (",c,m);
            for (i=0; i<m; i++) printf("%llu,",p[i]);
            printf("\b)\n");
        }        
    }

    return EXIT_SUCCESS;
}

こんな感じです。

出力結果
1: 5: (12496,14288,15472,14536,14264)
2: 28: (14316,19116,31704,47616,83328,177792,295488,629072,589786,294896,358336,418904,366556,274924,275444,243760,376736,381028,285778,152990,122410,97946,48976,45946,22976,22744,19916,17716)
3: 4: (1264460,1547860,1727636,1305184)
4: 4: (2115324,3317740,3649556,2797612)
5: 4: (2784580,3265940,3707572,3370604)
6: 4: (4938136,5753864,5504056,5423384)
7: 4: (7169104,7538660,8292568,7520432)
8: 4: (18048976,20100368,18914992,19252208)
9: 4: (18656380,20522060,28630036,24289964)
10: 4: (28158165,29902635,30853845,29971755)
11: 4: (46722700,56833172,53718220,59090084)
12: 4: (81128632,91314968,96389032,91401368)
13: 4: (174277820,205718020,262372988,210967684)
14: 4: (209524210,246667790,231439570,230143790)
15: 4: (330003580,363003980,399304420,440004764)
16: 4: (498215416,506040584,583014136,510137384)
17: 9: (805984760,1268997640,1803863720,2308845400,3059220620,3367978564,2525983930,2301481286,1611969514)
18: 8: (1095447416,1259477224,1156962296,1330251784,1221976136,1127671864,1245926216,1213138984)
19: 4: (1236402232,1369801928,1603118392,1412336648)
20: 8: (1276254780,2299401444,3071310364,2303482780,2629903076,2209210588,2223459332,1697298124)
21: 4: (1799281330,2267877710,2397470866,1954241390)
22: 4: (2387776550,2497625050,2550266150,2506553050)
23: 4: (2717495235,3509525565,3977471043,3100575933)
24: 4: (2879697304,3320611496,3364648984,3147575336)
25: 4: (3705771825,3890616975,4298858865,4659093135)
26: 4: (4424606020,5186286908,4720282996,4993345292)
27: 4: (4823923384,5708253896,5513075704,5196238856)
28: 4: (5373457070,5406735730,5575049870,5983131730)
29: 4: (8653956136,9890235704,9468980296,9237894104)
30: 4: (15837081520,23967995792,26042149708,21105018164)
31: 4: (17616303220,20012014220,25854330388,22095024044)
32: 6: (21548919483,23625285957,24825443643,26762383557,25958284443,23816997477)
33: 4: (21669628904,28986647896,25367088104,24111275896)
34: 4: (44379752648,59472079672,57414289928,50520737272)
35: 4: (73636082872,85180941128,80241838072,84123459128)
36: 4: (88585861815,90937094985,90251247735,90965321865)
37: 4: (90568599176,101073426424,99587052776,100773510424)
38: 6: (90632826380,101889891700,127527369100,159713440756,129092518924,106246338676)
39: 4: (91411869465,96182575335,117001337625,113863886055)

39個と少ないですが、11桁まですべて探索して39個なので、かなり時間が掛かることが予想出来ますね。

現時点で社交数について解っていることは、
4個組、5個組、6個組、8個組、9個組、28個組の存在は確認されているが、
3個組、7個組、10個組、…、27個組、29個組以上などが存在するかは未解決です。

プログラムによって、多少大きな社交数が解ってきたので、それをキーワードに検索してみると、ネットではもっと大きな社交数が確認出来ました。

728712583206303398190242618687042113752467214811108993257424171860528594567924190924670925
=3^5*5^2*19*31*41*219707*302203120345042452118191021599*74811436986632321880273947630151066444616891487

(1+3+9+27+81+243)
*(1+5+25)
*(1+19)
*(1+31)
*(1+41)
*(1+219707)
*(1+302203120345042452118191021599)
*(1+74811436986632321880273947630151066444616891487)
-728712583206303398190242618687042113752467214811108993257424171860528594567924190924670925
=777912361559506017106924016411985798162174755045418568804828526237301132540795410854017075
=3^5*5^2*19*31*41*219707*24134668888891652793753744940710524377095337065967694437989536691048774192767

(1+3+9+27+81+243)
*(1+5+25)
*(1+19)
*(1+31)
*(1+41)
*(1+219707)
*(1+24134668888891652793753744940710524377095337065967694437989536691048774192767)
-777912361559506017106924016411985798162174755045418568804828526237301132540795410854017075
=830433913470334951680671459201718136927391998068006241413850347605300258889341926931859405
=3^4*5*31*43*47*641*2341855521657031*322605134371499255501969886869*67582249501685963413963728527115449

(1+3+9+27+81)
*(1+5)
*(1+31)
*(1+43)
*(1+47)
*(1+641)
*(1+2341855521657031)
*(1+322605134371499255501969886869)
*(1+67582249501685963413963728527115449)
-830433913470334951680671459201718136927391998068006241413850347605300258889341926931859405
=777912361559506017106924016411985821960528418729797387983992973984632366735221369340524595
=3^4*5*31*43*47*641*2341855521657031*20423469187068442175351325869179832174429376379362479247163777619

(1+3+9+27+81)
*(1+5)
*(1+31)
*(1+43)
*(1+47)
*(1+641)
*(1+2341855521657031)
*(1+20423469187068442175351325869179832174429376379362479247163777619)
-777912361559506017106924016411985821960528418729797387983992973984632366735221369340524595
=728712583206303398190242618687042113752467214811108993257424171860528594567924190924670925

あまりにも大きすぎて、私のパソコンでは因数分解すら終わりません。

728712583206303398190242618687042113752467214811108993257424171860528594567924190924670925
777912361559506017106924016411985798162174755045418568804828526237301132540795410854017075
830433913470334951680671459201718136927391998068006241413850347605300258889341926931859405
777912361559506017106924016411985821960528418729797387983992973984632366735221369340524595

90桁の4個組です。
今回のプログラム
のフォーマットで記述するならば、

5410: 4: (728712583206303398190242618687042113752467214811108993257424171860528594567924190924670925,777912361559506017106924016411985798162174755045418568804828526237301132540795410854017075,830433913470334951680671459201718136927391998068006241413850347605300258889341926931859405,777912361559506017106924016411985821960528418729797387983992973984632366735221369340524595)
当然ですが、このプログラムでは64ビットの最大値/10までしか出来ず、90桁なんて夢のようなはなしですので、あしからず。

本気でやるならば、多倍長プログラミングをする必要があるだろうし、もっと高速なアルゴリズムを考える必要があるだろうし、最大が28個組かどうかも確定していないので、その辺も考慮する必要があるだろうし、もっと高速なスパコンなどを利用したり、分散型にしたり、とにかくパソコン1台でってわけにはいかないんだろう。


ではでは
 

 


Viewing all articles
Browse latest Browse all 5376

Trending Articles