まず、しらみつぶしに調べてみましょう。といってもこんな風にやるのは無理なので、数を小さくします。N = 10、M = 7としてみました。
#include <iostream> #include <algorithm> #include <functional> const int N = 10; const int M = 7; int c[M]; bool is_trianble(int *a) { return a[0] < a[1] + a[2]; } int num_iteration(int *a) { std::sort(a, a + M, std::greater<int>()); for(int k = 1; k < M - 1; k++) { if(is_trianble(a + k - 1)) return k; } return M - 1; } void count(int *first, int *last) { if(first == last) { int n = num_iteration(first - M); c[n]++; } else { for(int k = 1; k <= N; k++) { *first = k; count(first + 1, last); } } } void main() { std::fill(c, c + M, 0); int a[M]; count(a, a + M); for(int k = 1; k < M; k++) std::cout << k << " " << c[k] << std::endl; }
1 9686925 2 249487 3 48258 4 9450 5 5880 6 0
この方法では限界があるので、今度は疑似乱数を使ってみましょう。
// 省略 int rand_range(int a, int b) { int n = rand(); return a + n * (b - a + 1) / RAND_MAX; } // 省略 void init(int *a) { for(int n = 0; n < M; n++) a[n] = rand_range(1, N); } void count() { int a[M]; for(int k = 0; k < (int)1e7; k++) { init(a); const int n = num_iteration(a); c[n]++; } for(int k = 0; k < M; k++) std::cout << a[k] << " "; std::cout << std::endl; } void main() { std::fill(c, c + M, 0); int t = timeGetTime(); count(); std::cout << (timeGetTime() - t) * 1e-3 << std::endl; for(int k = 1; k < M; k++) std::cout << k << " " << c[k] << std::endl; }
1 9686617 2 250094 3 48127 4 9450 5 5712 6 0
悪くないですね。
他の場合も、N = 20にすると、
1 9687247 2 250750 3 48438 4 8101 5 3464 6 2000
上の方はあまり変わらないですね。このへんは直感と変わらないと思います。
N = 100として、Mを変えて1回で終わる場合をカウントしてみましょう。Mを3から10とします。
3 5000652 4 7498888 5 8750729 6 9374994 7 9688164 8 9843646 9 9922118 10 9960882
どうやら1回目で三角形になる確率は、
pM ≒ 1 - 22-M
となるようですね。