import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; class Q6_892 { // 1~MAX_BALL_NUMBERの数が書かれた球を使う static final int MAX_BALL_NUMBER = 15; static boolean abort; { // 5個の球を使って21を作る test(5, 21, false, true, false); // 6個~15個の球を使って21を作る // 1個でも結果が見つかれば計算を打ち切る for(int i = 6; i <= MAX_BALL_NUMBER; i++) { test(i, 21, false, true, true); } } static void test(int n, int m, boolean reduce, boolean view, boolean censoring) { abort = false; ArrayList<int[]> list = new ArrayList<>(); // 処理 forEach(reduce, n, (int[] p) -> { if (test(m, p)) { if (reduce) { // 配列の要素を1個左に回転させる int[] is = new int[p.length]; for(int i = 0; i < p.length - 1; i++) { is[i] = p[i + 1]; } is[p.length - 1] = p[0]; list.add(is); } else { } abort = censoring; } }); if (reduce) { int compare = 0; for(int i = 0; i < n && compare == 0; i++) { } return compare; }); } // 結果表示 "N=%d,M=%d...%d個の結果が見つかりました 計算時間%,dms%n", n, m, list.size(), TimeUnit.NANOSECONDS.toMillis(e - s)); if (view) { for (int[] is : list) { } } } /** * ballsの配列を使って1~mの数値を作れるかどうかを調べる */ static boolean test(int m, int[] balls) { boolean[] flags = new boolean[m + 1]; int sum = 0; // ballsを全部足した合計値のフラグを立てる for (int i = 0; i < balls.length; i++) { sum += balls[i]; } if (sum <= m) flags[sum] = true; // 1~m-1個の連続した球の数の合計値のフラグを立てる for (int i = 0; i < balls.length; i++) { sum = 0; for (int j = 0; j < balls.length - 1; j++) { sum += balls[(i + j) % balls.length]; if (sum > m) break; flags[sum] = true; } } for (int i = 1; i <= m; i++) { if (!flags[i]) return false; } return true; } /** * 順列を生成してConsumerに処理を投げる * @param reduce 計算量削減させるかどうか * @param num 球の数 * @param c */ static void forEach(boolean reduce, int num, Consumer<int[]> c) { // 計算量削減のために最初3個をA,B,Cとした場合 B=1, C<Aとなるようにする。(基点の位置確定と反転の回避) if (reduce) { int[] perm = new int[num]; boolean[] used = new boolean[MAX_BALL_NUMBER + 1]; perm[1] = 1; used[1] = true; for (int i = 2; i <= MAX_BALL_NUMBER - 1; i++) { perm[2] = i; used[i] = true; for (int j = i + 1; j <= MAX_BALL_NUMBER; j++) { perm[0] = j; used[j] = true; p(perm, used, 3, c); used[j] = false; } used[i] = false; } } else // 計算量削減せずに全パターン調べる { p(new int[num], new boolean[MAX_BALL_NUMBER + 1], 0, c); } } /** * 再帰で順列生成 */ private static void p(int[] perm, boolean[] used, int p, Consumer<int[]> c) { if (perm.length == p) { c.accept(perm); return; } for (int i = 1; i <= MAX_BALL_NUMBER && !abort; i++) { if (used[i]) continue; used[i] = true; perm[p] = i; p(perm, used, p + 1, c); used[i] = false; } } }
Standard input is empty
N=5,M=21...10個の結果が見つかりました 計算時間228ms [1, 3, 10, 2, 5] [1, 5, 2, 10, 3] [2, 5, 1, 3, 10] [2, 10, 3, 1, 5] [3, 1, 5, 2, 10] [3, 10, 2, 5, 1] [5, 1, 3, 10, 2] [5, 2, 10, 3, 1] [10, 2, 5, 1, 3] [10, 3, 1, 5, 2] N=6,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 8] 計算を打ち切りました N=7,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7] 計算を打ち切りました N=8,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 8, 7] 計算を打ち切りました N=9,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 8, 7, 10] 計算を打ち切りました N=10,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 計算を打ち切りました N=11,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13] 計算を打ち切りました N=12,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13] 計算を打ち切りました N=13,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 計算を打ち切りました N=14,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15] 計算を打ち切りました N=15,M=21...1個の結果が見つかりました 計算時間0ms [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 計算を打ち切りました