問題が「約数全ての列挙」であれば,整数a
の約数にはa
自身も含むはずです.が,上のコードでは約数リストにはa
自身を含みません1.なので,このリストに追加で最後の出力ではa
も出力してあげる必要があると思いました.
a = int(input())
divisor = list()
for i in range(1, a):
if a % i == 0:
divisor.append(i)
if a == sum(divisor):
print(divisor, a) # 最後にaも一緒に出力する
else:
print(0)
ただ,この書き方だと出力が以下のようになって
標準出力例,a = 8128
[1, 2, 4, 8, 16, 32, 64, 127, 254, 508, 1016, 2032, 4064] 8128
少し変なので,range(1, a)
だったのをrange(1, a + 1)
にすることで約数全てを求めるようにしたうえで条件文2を変更して
a = int(input())
divisor = list()
for i in range(1, a + 1): # 1からa + 1未満まで求める
if a % i == 0:
divisor.append(i)
if a * 2 == sum(divisor): # 条件文の変更
print(divisor)
else:
print(0)
とすればきれいに出力されると思います.また,listの標準出力についてくる角括弧も省いた上でPythonicな書き方で
低速な約数列挙
a = int(input())
divisor = [i for i in range(1, a + 1) if a % i == 0]
print(', '.join(map(lambda x: str(x), divisor)) if a * 2 == sum(divisor) else 0)
と書くのもありだと思います.また,時間計算量の観点から上のコードでは整数$N$に対して$O(N)$の実行時間がかかるコードになっており,約数を求めるアルゴリズムの中では低速なものが実装されています.$O(\sqrt{N})$にまで計算量を削減して
高速な約数列挙
divisor = list()
for i in range(1, a):
if i * i > a:
break
if a % i == 0:
divisor.append(i) # iで割り切れたら約数
if i * i != a:
divisor.append(a // i) # そのときaをiで割った商も約数
と書くこともできます.こちらで試したそれぞれの約数列挙の実行時間は
数 |
完全数 |
$O(N)$なコード |
$O(\sqrt{N})$なコード |
8128 |
Yes |
$191$$[\mu{\rm s}]$ |
$5.38$$[\mu{\rm s}]$ |
123456 |
No |
$3.21$$[{\rm ms}]$ |
$0.02$$[{\rm ms}]$ |
33550336 |
Yes |
$ 842$$[{\rm ms}]$ |
$0.26$$[{\rm ms}]$ |
123456789 |
No |
$3.23$$[{\rm s}]$ |
$0.0005$$[{\rm s}]$ |
8589869056 |
Yes |
$750$$[{\rm s}]$ |
$0.007$$[{\rm s}]$ |
137438691328 |
Yes |
多分半日ぐらい(予測) |
$0.032$$[{\rm s}]$ |
2305843008139952128 |
Yes |
数千~数万年(予測) |
$150$$[{\rm s}]$ |
になります.判定させる値にもよりますが,実行時間が短いに越したことはありません.参考までに.