blob: ed060528c457330c13bd23cace2cd7b36d6b0403 [file] [log] [blame]
/*
* 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;
}
}