arXiv探訪

興味の赴くままに数学するだけ

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秒くらい。