午後のひとときに、プログラミングの問題を考えてみる。
婚約数とは、
ある自然数Aの1とAを除いた約数の和がB、
Bの1とBを除いた約数の和がA、
となる(A,B)の組み合わせです。
問題
婚約数の組をAを昇順で列挙するプログラムを組め。
シンキングタ~イム
とりあえず、2通りの方法で組んでみました。
konyakusu1.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, s;
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);
s = sqrtl(p);
for (i=2,q=0; i<s; i++) {
if ( p%i == 0 ) {
q += i+p/i;
}
}
if ( p%i == 0 && i < p/i ) {
q += i+p/i;
} else if ( p%i == 0 ) {
q += i;
}
if ( p >= q ) continue;
s = sqrtl(q);
for (i=2,r=0; i<s; i++) {
if ( q%i == 0 ) {
r += i+q/i;
}
}
if ( q%i == 0 && i < q/i ) {
r += i+q/i;
} else if ( q%i == 0 ) {
r += i;
}
if ( p == r ) {
c++;
printf("%llu: (%llu,%llu)\n",c,p,q);
}
}
return EXIT_SUCCESS;
}
これは、約数の候補を検索して、純粋に足し込んでいます。
konyakusu2.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;
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;
for (i=3; i<=s; i+=2) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
q *= k;
}
if ( t > 1 ) {
q *= 1+t;
}
q -= 1+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;
for (i=3; i<=s; i+=2) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
r *= k;
}
if ( t > 1 ) {
r *= 1+t;
}
r -= 1+q;
if ( p == r ) {
c++;
printf("%llu: (%llu,%llu)\n",c,p,q);
}
}
return EXIT_SUCCESS;
}
これは、素因数分解をして、公式で約数の総和を求めている。
konyakusu1.exe と konyakusu2.exe は、コンパイラによっては速度が違うかもしれないが、私の環境では後者の方が速度が出ました。
また、konyakusu1.c は、これ以上の枝刈りなどが考えにくいが、konyakusu2.c は、素因数分解のアルゴリズムの部分で、まだまだ改善の余地がある。
というわけで、素因数分解の方法で、もう少し改善してみる。
簡単に言えば、素因数の候補を出来るだけ素数になるように確率を上げます。
konyakusu3.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;
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;
for (i=5; i<=s; i+=4) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
q *= k;
i += 2;
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
q *= k;
}
if ( t > 1 ) {
q *= 1+t;
}
q -= 1+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;
for (i=5; i<=s; i+=4) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
r *= k;
i += 2;
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
r *= k;
}
if ( t > 1 ) {
r *= 1+t;
}
r -= 1+q;
if ( p == r ) {
c++;
printf("%llu: (%llu,%llu)\n",c,p,q);
}
}
return EXIT_SUCCESS;
}
konyakusu2.c の素因数分解の素数になる確率を高めてみました。
私の環境では、konyakusu2.exe よりも konyakusu3.exe のほうが速度が出ています。
konyakusu4.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[8] = {4,2,4,2,4,6,2,6},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;
for (i=7,n=0; i<=s; i+=a[n],n=(n+1)%8) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
q *= k;
}
if ( t > 1 ) {
q *= 1+t;
}
q -= 1+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;
for (i=7,n=0; i<=s; i+=a[n],n=(n+1)%8) {
j = i;
k = 1;
while ( t%i == 0 ) {
k += j;
t /= i;
j *= i;
}
r *= k;
}
if ( t > 1 ) {
r *= 1+t;
}
r -= 1+q;
if ( p == r ) {
c++;
printf("%llu: (%llu,%llu)\n",c,p,q);
}
}
return EXIT_SUCCESS;
}
konyakusu2.c は、約1/2=50%
konyakusu3.c は、約4/6=2/3=66.{6}%
konyakusu4.c は、約22/30=11/15=73.{3}%
枝刈りされています。
出力結果1: (48,75)
2: (140,195)
3: (1050,1925)
4: (1575,1648)
5: (2024,2295)
6: (5775,6128)
7: (8892,16587)
8: (9504,20735)
9: (62744,75495)
10: (186615,206504)
11: (196664,219975)
12: (199760,309135)
13: (266000,507759)
14: (312620,549219)
15: (526575,544784)
16: (573560,817479)
17: (587460,1057595)
18: (1000824,1902215)
19: (1081184,1331967)
20: (1139144,1159095)
21: (1140020,1763019)
22: (1173704,1341495)
23: (1208504,1348935)
24: (1233056,1524831)
25: (1236536,1459143)
26: (1279950,2576945)
27: (1921185,2226014)
28: (2036420,2681019)
29: (2102750,2142945)
30: (2140215,2421704)
31: (2171240,3220119)
32: (2198504,3123735)
33: (2312024,3010215)
34: (2580864,5644415)
35: (2958500,3676491)
36: (4012184,4282215)
37: (4311024,7890575)
38: (5088650,6446325)
39: (5416280,7509159)
40: (6081680,9345903)
41: (6618080,12251679)
42: (7460004,10925915)
43: (7875450,16381925)
44: (8713880,13693959)
45: (8829792,18845855)
46: (9247095,10106504)
47: (12146750,16247745)
48: (12500865,12900734)
49: (13922100,31213899)
50: (14371104,28206815)
51: (22013334,37291625)
52: (22559060,26502315)
53: (23379224,26525415)
54: (23939685,31356314)
55: (26409320,41950359)
56: (27735704,27862695)
57: (28219664,32014575)
58: (33299000,58354119)
59: (34093304,43321095)
60: (37324584,80870615)
61: (40818855,42125144)
62: (41137620,84854315)
63: (49217084,52389315)
64: (52026920,85141719)
65: (52601360,97389039)
66: (61423340,88567059)
67: (62252000,93423519)
68: (64045904,70112175)
69: (66086504,69090615)
70: (66275384,87689415)
71: (68337324,141649235)
72: (72917000,115780599)
73: (76011992,87802407)
74: (77723360,145810719)
75: (89446860,197845235)
76: (93993830,99735705)
77: (94713300,240536075)
78: (94970204,96751395)
79: (97797104,114332175)
80: (100256480,174080799)
81: (101366342,105993657)
82: (101589320,168669879)
83: (102019644,162156995)
84: (106004024,129081735)
85: (106524264,231472535)
86: (114859884,164799635)
87: (116329136,183651663)
88: (116481464,128825415)
89: (116540304,204064175)
90: (117106064,133592175)
91: (117869940,261412235)
92: (128707425,205556894)
93: (130016744,166335255)
94: (130304888,184191111)
95: (134064584,140687415)
96: (139829624,165507975)
97: (142287992,193773447)
98: (147041504,150157215)
99: (152340944,233348655)
100: (153582624,374770655)
100組を列挙してみました。
実は、今まで見つかっている婚約数の組は、
偶数と奇数の組み合わせしか見つかっておりません。
染色体の数から、奇数を男性、偶数を女性と考えると、男女のペアしか結婚出来ないという感じです。
婚約数に似たもので、友愛数や社交数というものがありますが、また別の機会に。
ではでは
knifeのmy Pick