一道算術題🧮背後的算法迭代

前段時間看到一道題,覺得是無聊開會時絕佳的消遣項目:

一個 10 位數 ab,cdef,ghij,各位不同,且滿足:

有天開了半天會,結果還是沒有手算出來。就想着用腳本跑跑唄。

第一版·傻大粗黑

10.times do |a|
    10.times do |b|
        10.times do |c|
            10.times do |d|
                10.times do |e|
                    10.times do |f|
                        10.times do |g|
                            10.times do |h|
                                10.times do |i|
                                    10.times do |j|
                                        next if a % 1 != 0
                                        next if "#{a}#{b}".to_i % 2 != 0
                                        next if "#{a}#{b}#{c}".to_i % 3 != 0
                                        next if "#{a}#{b}#{c}#{d}".to_i % 4 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}".to_i % 5 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}".to_i % 6 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}".to_i % 7 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}".to_i % 8 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}".to_i % 9 != 0
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}#{j}".to_i % 10 != 0
                                        
                                        next if [a, b, c, d, e, f, g, h, i, j].uniq.size != 10
                                        
                                        puts "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}#{j}"
                                    end
                                end
                            end
                        end
                    end
                end
            end        
        end 
    end
end

跑了幾分鐘還沒出結果。想着不對啊。算了一下:就算每秒算 100,0000 條,跑完 10^10 也得 2.7 個小時。等不起,等不起☹️。

第二版 ·剪枝✂️:

稍稍改進下吧。原本是預計會提高一倍,結果出奇地塊😱:0.18 秒找到答案 3816547290

10.times do |a|
    next if a % 1 != 0
    10.times do |b|
        next if "#{a}#{b}".to_i % 2 != 0
        10.times do |c|
            next if "#{a}#{b}#{c}".to_i % 3 != 0
            10.times do |d|
                next if "#{a}#{b}#{c}#{d}".to_i % 4 != 0
                10.times do |e|
                    next if "#{a}#{b}#{c}#{d}#{e}".to_i % 5 != 0
                    10.times do |f|
                        next if "#{a}#{b}#{c}#{d}#{e}#{f}".to_i % 6 != 0
                        10.times do |g|
                            next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}".to_i % 7 != 0
                            10.times do |h|
                                next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}".to_i % 8 != 0
                                10.times do |i|
                                    next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}".to_i % 9 != 0
                                    10.times do |j|
                                        next if "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}#{j}".to_i % 10 != 0
                                        next if [a, b, c, d, e, f, g, h, i, j].uniq.size != 10
                                        
                                        puts "#{a}#{b}#{c}#{d}#{e}#{f}#{g}#{h}#{i}#{j}"
                                    end
                                end
                            end
                        end
                    end
                end
            end        
        end 
    end
end

第三版·用上排列:

想到如果一開始就用 0 ~ 9 的排列來排查,應該會省很多計算吧。

(0..9).to_a.permutation.each do |ary|
    found_it = true
    ary.each_with_index do |v, i|
        if ary[0 .. i].join.to_i % (i + 1) != 0
            found_it &= false
        end
    end
    puts ary.join if found_it
end

代碼是省了不少,但反而慢了很多(101.8 秒),怪了🤔。加個 break 試試:

(0..9).to_a.permutation.each do |ary|
    found_it = true
    ary.each_with_index do |v, i|
        if ary[0 .. i].join.to_i % (i + 1) != 0
            found_it &= false
            break # 如果是 next 就沒用。
        end
    end
    puts ary.join if found_it
end

快了一點 17.3 秒。

第四版·手工計算

當然,我們的終極夢想是能筆算出來😝。

(挖坑🕳️)


從這個例子可以看出,數學不過是在找出內在結構,罷了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章