裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

「ループ・トラッキング」問題

2017年10月26日 | ブログラミング

「ループ・トラッキング」問題

締め切りが 2017/10/26 10:00 AM なので,その 1 分後に投稿されるように予約

自然数 n に対し、関数 Fn(x) を次のように定義します(floor():床関数)。

例えば n=10, x=1 のとき、F10(1) = floor(4×1×9÷10) = 3 です。
 
さて、整数 k(0 ≦ k ≦ n)に対して、関数 Fn による変換を繰り返し行います。
例えば n=10, k=1 のとき、F10 で 1 を変換すると 3 となり、さらに変換すると 8 となります。
以降、1 → 3 → 8 → 6 → 9 → 3 → 8 → … と値が変わっていきます。
 
このように変換を繰り返したときに、今までに出た値が再度現れるまでの変換回数を G(n, k) と定義します。
 
例えば G(10, 1)=5 です。5 回目の変換で 3 の値が再度現れていることが分かります(上の太字部分)。
同様に、G(10, 6)=4, G(10, 0)=1, G(10, 5)=3, G(20, 6)=8 となることが確かめられます。
 
0 以上 n 以下の全ての整数 k に対する G(n, k) の和を H(n) と定義します。
 
例えば H(10)=42, H(20)=91, H(100)=1118 となることが確かめられます。
 
標準入力から、自然数 n(1 ≦ n ≦ 3×105)が与えられます。
標準出力に H(n) の値を出力するプログラムを書いてください。
 
=============================================================================

R で簡素に書くと以下の通り。しかし,実行時間は掛かる。

f = function(n, x) {
    floor(4*x*(n-x)/n)
}

g = function(n, k) {
    nxt = pool = k
    count = 0
    repeat {
        nxt = f(n, nxt)
        count = count+1
        if (nxt %in% pool) {
            return(count)
        }
        pool = c(pool, nxt)
    }
}

h = function(n) {
    sum = 0
    for (k in 0:n) {
        sum = sum+g(n, k)
    }
    sum
}

h(35) # 226
h(350) # 8877
h(1908) # 99344
h(61922) # 8504585
h(99999) # 35499513
h(299997) # 204796803

> h(35) # 226
[1] 226
> h(350) # 8877
[1] 8877
> h(1908) # 99344
[1] 99344

Java や C++ で,いくつものこそくな手段を弄して書いても,h(299997) には,手元のパソコンでも 1.5 sec. ほど掛かってしまうのだ。

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        if (false) {
            Scanner cin = new Scanner(System.in);
            String line;
            line = cin.nextLine();
            int n = Integer.parseInt(line);
            h(n);
        } else {
             long start = System.currentTimeMillis();
            // h(35); // 226
            //h(350); // 8877
            // h(1908); // 99344
            // h(61922); // 8504585
            // h(99999); // 35499513
            // h(299997); // 204796803
             long end = System.currentTimeMillis();
             System.out.println((end - start) + "ms");
        }
    }

    static void h(int n) {
        boolean[] exists = new boolean[n + 1];
        double n4 = 4.0 / n;
        int sum = 0;
        int[] suf = new int[n + 1];
        for (int k = 0; n >= k; k++) {
            int next;
            next = k;
            exists[next] = true;
            int c = 0;
            suf[c++] = next;
            int count = 0;
            for (;;) {
                next = (int) (n4 * next * (n - next));
                count++;
                if (exists[next]) {
                    sum += count;
                    break;
                }
                exists[next] = true;
                suf[c++] = next;
            }
            for (int i = 0; i < c; i++) {
                exists[suf[i]] = false;
            }
        }
        System.out.println(sum);
    }

}

コメント    この記事についてブログを書く
  • Twitterでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« urinomics !!! | トップ | カーペット »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事