2^i * 3^j * 5^k なる整数 from どう書く?org

| # Comments
どう書く?orgにて、なぜかどうしても気になる問題があって頭を悩ませてしょうがないのでまじめに考えてみました。

2^i * 3^j * 5^k なる整数

2^i * 3^j * 5^k の形で表される整数を小さい方から順に 100 個列挙するプログラムを書いてください。 i, j, k は 0 以上の整数です。アルゴリズムのオーダーについても考えてみてください。

例えば最初の 10 個は次のようになります:

 1 = 2^0 * 3^0 * 5^0
 2 = 2^1 * 3^0 * 5^0
 3 = 2^0 * 3^1 * 5^0
 4 = 2^2 * 3^0 * 5^0
 5 = 2^0 * 3^0 * 5^1
 6 = 2^1 * 3^1 * 5^0
 8 = 2^3 * 3^0 * 5^0
 9 = 2^0 * 3^2 * 5^0
10 = 2^1 * 3^0 * 5^1
12 = 2^2 * 3^1 * 5^0

※解答では i, j, k の各値を示す必要はありません。

Java版

package q206;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Q206 {

    public static void main(String[] args) {
        Q206 q206 = new Q206(2, 3, 5);
        q206.printUpTo(100);
    }

    private final Map<Long, long[]> a = new TreeMap<Long, long[]>();

    private final int[] primes;

    private final Crawler crawler;

    /**
     * @param primes
     */
    public Q206(int... primes) {
        Arrays.sort(primes);
        this.primes = primes;
        long[] one = new long[primes.length];
        a.put(1L, one);
        crawler = new Crawler(Arrays.copyOf(one, one.length), 0);
    }

    /**
     * @param limit
     */
    public void printUpTo(int limit) {
        for(long i = 1; a.size() < limit; i *= primes[primes.length - 1]) {
            crawler.crawl(i);
        }
        int i = 0;
        for(Map.Entry<Long, long[]> entry : a.entrySet()) {
            StringBuilder builder = new StringBuilder(String.format("%3d : ",
                    i + 1));
            builder.append(String.format("%4d = %2d^%2d", entry.getKey(),
                    primes[0], entry.getValue()[0]));
            for(int j = 1; j < primes.length; j++) {
                builder.append(String.format(" * %2d^%2d", primes[j], entry
                        .getValue()[j]));
            }
            System.out.println(builder.toString());

            i++;
            if(i >= limit) {
                break;
            }
        }
    }

    private class Crawler {

        private final long[] pow;

        private final int idx;

        private long current = 1;

        private final List<Crawler> crawlers = new ArrayList<Crawler>();

        public Crawler(long[] pow, int idx) {
            this.pow = pow;
            this.idx = idx;
            for(int i = 0; i < primes.length; i++) {
                for(int j = 0; j < pow[i]; j++) {
                    current *= primes[i];
                }
            }
            if(idx < pow.length - 1) {
                crawlers.add(new Crawler(Arrays.copyOf(pow, pow.length),
                        idx + 1));
            }
        }

        public void crawl(long limit) {
            while(current < limit) {
                current *= primes[idx];
                pow[idx]++;
                a.put(current, Arrays.copyOf(pow, pow.length));
                if(idx < pow.length - 1) {
                    crawlers.add(new Crawler(Arrays.copyOf(pow, pow.length),
                            idx + 1));
                }
            }
            for(Crawler crawler : crawlers) {
                crawler.crawl(limit);
            }
        }
    }

}

Ruby版

class Q206
  
  attr_reader :a, :primes
  
  def initialize(primes)
    @primes = primes.sort
    one = Array.new(primes.size){0}
    @a = { 1 => one }
    @crawler = Crawler.new(@primes, @a, one.dup, 0)
  end
  
  def upto(limit)
    i = 1
    while @a.size < limit
      @crawler.crawl(i)
      i *= @primes[-1]
    end
    j = 0
    @a.keys.sort.each do |key|
      j += 1
      yield j, key, @a[key]
      if j >= limit
        break;
      end
    end
  end
  
  class Crawler
    
    def initialize(primes, a, pow, idx)
      @primes = primes
      @a = a
      @pow = pow
      @idx = idx
      @cur = 1
      primes.size.times do |i|
        pow[i].times do
          @cur *= primes[i]
        end
      end
      @crawlers = []
      if idx < pow.size - 1
        @crawlers.push(Crawler.new(@primes, @a, @pow.dup, @idx+1))
      end
    end
    
    def crawl(limit)
      while @cur < limit
        @cur *= @primes[@idx]
        @pow[@idx] += 1
        @a[@cur] = @pow.dup
        if @idx < @pow.size - 1
          @crawlers.push(Crawler.new(@primes, @a, @pow.dup, @idx+1))
        end
      end
      @crawlers.each do |crawler|
        crawler.crawl(limit)
      end
    end
    
  end
  
end


q206 = Q206.new([2,3,5])
q206.upto(100) do |i,num,a|
  printf "%3d : %4d = %2d^%2d", i, num, q206.primes[0], a[0]
  1.upto(q206.primes.size-1) do |j|
    printf " * %2d^%2d", q206.primes[j], a[j]
  end
  puts ''
end
comments powered by Disqus

Twitter Icon

AdSense

Creative Commons License
このブログはクリエイティブ・コモンズでライセンスされています。
Powered by Movable Type 5.14-ja

Google検索

カスタム検索

2013年10月

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31