juliaで組合せ問題を解く
mathtodonより
問題 相異なる5つの正の自然数でどの2つの積も5つの総和で割り切れるようなものの内,なるべく小さいものの組みを答えよ
上手い方法を知らないのでベタ書き。だれか詳しい人教えてください。
flag = true sum = 15 @inline function d(p::Int64, q::Int64) return (p*q)%sum == 0 end @inline function slt(a, b) if a%b==0 return fld(a, b)-1 else return fld(a, b) end end @time while flag for l=4:slt(sum-6, 2) for i=1:(l-3) for j=(i+1):(l-2) for k=(j+1):(l-1) m=sum-i-j-k-l if m <= l break end if d(i, j) && d(i, k) && d(i, l) && d(i, m) && d(j, k) && d(j, l) && d(j, m) && d(k, l) && d(k, m) && d(l, m) @show i, j, k, l, m flag = false break end end end end end sum += 1 end
自分の環境だと12秒以内。
(i, j, k, l, m) = (15, 30, 45, 60, 75) 11.232019 seconds (68.38 M allocations: 2.006 GiB, 1.59% gc time)
ちなみに最初の12個
(i, j, k, l, m) = (15, 30, 45, 60, 75) (i, j, k, l, m) = (16, 32, 48, 64, 96) (i, j, k, l, m) = (17, 34, 51, 68, 119) (i, j, k, l, m) = (17, 34, 51, 85, 102) (i, j, k, l, m) = (18, 36, 54, 72, 144) (i, j, k, l, m) = (18, 36, 54, 90, 126) (i, j, k, l, m) = (18, 36, 72, 90, 108) (i, j, k, l, m) = (19, 38, 57, 76, 171) (i, j, k, l, m) = (19, 38, 57, 95, 152) (i, j, k, l, m) = (19, 38, 76, 95, 133) (i, j, k, l, m) = (19, 57, 76, 95, 114) (i, j, k, l, m) = (19, 38, 57, 114, 133)
追記
寝ながら考え直したら0.08秒まで短縮できました。
@inline function check(p::Int64, q::Int64, total) return (p*q)%total == 0 end function calc(N::Int64) counter = 0 total = a = s = [0, 0, 0, 0, 0] total[1] = 15 while true for a[1] = 1:total[1] total[2] = total[1]-a[1]*5 if (total[2] <= 0) break end s[1] = a[1] for a[2] = 1:total[2] total[3] = total[2]-a[2]*4 if (total[3] <= 0) break end s[2] = s[1]+a[2] if !check(s[1], s[2], total[1]) continue end for a[3] = 1:total[3] total[4] = total[3]-a[3]*3 if (total[4] <= 0) break end s[3] = s[2]+a[3] if !check(s[1], s[3], total[1]) continue end if !check(s[2], s[3], total[1]) continue end for a[4] = 1:total[4] a[5] = total[4]-a[4]*2 if (a[5] <= 0) break end s[4] = s[3]+a[4] if !check(s[1], s[4], total[1]) continue end if !check(s[2], s[4], total[1]) continue end if !check(s[3], s[4], total[1]) continue end s[5] = s[4]+a[5] if !check(s[1], s[5], total[1]) continue end if !check(s[2], s[5], total[1]) continue end if !check(s[3], s[5], total[1]) continue end if !check(s[4], s[5], total[1]) continue end @show s counter += 1 if (counter >= N) return end end end end end total += 1 end end @time calc(10)
s = [15, 30, 45, 60, 75] s = [16, 32, 48, 64, 96] s = [17, 34, 51, 68, 119] s = [17, 34, 51, 85, 102] s = [18, 36, 54, 72, 144] s = [18, 36, 54, 90, 126] s = [18, 36, 72, 90, 108] s = [19, 38, 57, 76, 171] s = [19, 38, 57, 95, 152] s = [19, 38, 57, 114, 133] 0.081676 seconds (21.75 k allocations: 1.098 MiB)
このプログラムだと、1個も10個もあまりかわりませんでした。メモリの関係上、起動直後は少し時間が掛かって0.3秒くらい。