/* * The Computer Language Benchmarks Game * http://shootout.alioth.debian.org/ * * Based on contribution of Eckehard Berns * Based on code by Heiner Marxen * and the ATS version by Hongwei Xi * convert to Java by The Anh Tran */ import java.util.concurrent.atomic.AtomicInteger; public final class fannkuch implements Runnable { private final int n; private final int[] flip_max_arr; private final AtomicInteger remain_task = new AtomicInteger(0); public static void main(String[] args) { int x = (args.length > 0) ? Integer.parseInt(args[0]) : 7; fannkuch f = new fannkuch(x); System.out.format("Pfannkuchen(%d) = %d\n", x, f.fank_game()); } public fannkuch(int N) { n = N; // hold flip_count result for each swap index flip_max_arr = new int[n]; } private final int fank_game() { Thread[] th = new Thread[Runtime.getRuntime().availableProcessors()]; for (int i = 0; i < th.length; i++) { th[i] = new Thread(this); th[i].start(); } print_30_permut(); for (Thread t : th) { try { t.join(); } catch (InterruptedException ie) { } } int mx = 0; for (int i : flip_max_arr) if (mx < i) mx = i; return mx; } // In order to divide tasks 'equally' for many threads, permut generation // strategy is different than that of original single thread. // this function will 'correctly' print first 30 permutations private final void print_30_permut() { // declare and initialize final int[] permutation = new int[n]; for ( int i = 0; i < n; i++ ) { permutation[i] = i; System.out.print((1 + i)); } System.out.println(); final int[] perm_remain = new int[n]; for ( int i = 1; i <= n; i++ ) perm_remain[i -1] = i; int numPermutationsPrinted = 1; for ( int pos_right = 2; pos_right <= n; pos_right++ ) { int pos_left = pos_right -1; do { // rotate down perm[0..prev] by one next_perm(permutation, pos_left); if (--perm_remain[pos_left] > 0) { if (numPermutationsPrinted++ < 30) { for (int i = 0; i < n; ++i) System.out.print((1 + permutation[i])); System.out.println(); } else return; for ( ; pos_left != 1; --pos_left) perm_remain[pos_left -1] = pos_left; } else ++pos_left; } while (pos_left < pos_right); } } public void run() { final int[] permutation = new int[n]; final int[] perm_remain = new int[n]; final int[] perm_flip = new int[n]; int pos_right; while ((pos_right = remain_task.getAndIncrement()) < (n - 1)) { int flip_max = 0; for (int i = 0; i < n - 1; i++) permutation[i] = i; permutation[pos_right] = (n - 1); permutation[n - 1] = (pos_right); for (int i = 1; i <= n; i++) perm_remain[i - 1] = i; int pos_left = n - 2; while (pos_left < n - 1) { // rotate down perm[0..r] by one next_perm(permutation, pos_left); if (--perm_remain[pos_left] > 0) { for (; pos_left != 1; --pos_left) perm_remain[pos_left - 1] = pos_left; if ((permutation[0] != 0) && (permutation[n - 1] != (n - 1))) { System.arraycopy(permutation, 0, perm_flip, 0, n); int flipcount = count_flip(perm_flip); if (flip_max < flipcount) flip_max = flipcount; } } else pos_left++; } // update max_flip foreach flipping position flip_max_arr[pos_right] = flip_max; } } // Take a permut array, continuously flipping until first element is '1' // Return flipping times private static final int count_flip(final int[] perm_flip) { // cache first element, avoid swapping perm[0] and perm[k] int v0 = perm_flip[0]; int tmp; int flip_count = 0; do { for (int i = 1, j = v0 - 1; i < j; ++i, --j) { tmp = perm_flip[i]; perm_flip[i] = perm_flip[j]; perm_flip[j] = tmp; } tmp = perm_flip[v0]; perm_flip[v0] = v0; v0 = tmp; flip_count++; } while (v0 != 0); // first element == '1' ? return flip_count; } // Return next permut, by rotating elements [0 - position] one 'step' // next_perm('1234', 2) -> '2314' private static final void next_perm(final int[] permutation, int position) { int perm0 = permutation[0]; for (int i = 0; i < position; ++i) permutation[i] = permutation[i + 1]; permutation[position] = perm0; } }