package av; import java.util.Arrays; import java.io.PrintStream; /** * Utility methods. To test, run with -ea (assertions enabled). */ public class AVUtil { private static final PrintStream out = System.out; /** * Modifies an array a in which entries are in 0..b-1 by moving to * the next sequence in lexicographic order, where index 0 has * lowest order (i.e., changes most frequently). For example, if * b=4 and a={2,2,3,0}, then upon return a={3,2,3,0}. After the * next call, a={0,3,3,0}. If a is already at the last sequence, * a is not modified and false is returned; otherwise, true is * returned. For example, if called on b=4 and a={3,3,3,3}, false * is returned and a is unmodified. */ public static boolean nxt_lex_lo(int b, int[] a) { int n=a.length, i=0; while (i=n) return false; a[i]++; i--; while (i >= 0) { a[i] = 0; i--; } return true; } public static boolean nxt_lex_lo_2d(int b, int[][] a) { int n=a.length, i=0; while (i=n) return false; nxt_lex_lo(b, a[i]); i--; while (i >= 0) { int m = a[i].length; for (int j=0; j=0; i--) { int d = a1[i] - a2[i]; if (d < 0) return -1; if (d > 0) return 1; } return 0; } public static boolean is_const(int[] a, int val) { int n = a.length; for (int i=0; i=n) return false; nxt_lex_lo(b, a[i]); i--; while (i >= 0) { int m = a[i].length; for (int j=0; j=0) { if (a[i] != b-1) break; i--; } if (i<0) return false; a[i]++; i++; while (i < n) { a[i] = 0; i++; } return true; } /** * Modifies a permutation array a by moving it to the next * permutation in increasing lexicographic order, where index 0 * has lowest order. a should be a permutation of 0..n-1, where n * is the length of a. For example, if a={1,2,3,0} then upon * return a={3,2,0,1}. If a is already at the last permutation, a * is not modified and false is returned; else true is returned. * For example, if a={0,1,2,3} then false is returned. */ public static boolean nxt_perm_lo(int[] a) { int n = a.length, i = 1; if (i >= n) return false; while (i=n) return false; int p = a[i], j = 0; while (a[j] < p) j++; assert j=0) { if (a[i]i; a[i] = a[j]; a[j] = p; Arrays.sort(a, i+1, n); // sort i+1..n-1 return true; } /** * Increments a partition. A k-partition of n (n>=1) is a k-tuple * of positive integers whose components sum to n. These k-tuples * can be ordered lexicographically. The orientation is 0-low. * Given such a partition, this method changes the partition to * the next partition under this order, if there is one. It * returns true if there was a next partition, false if there was * not one (in which case, the given partition is unmodified). * * Algorithm: start with (a_0,a_1,...,a_{k-1}). Working from left * (lowest index, 0), find the first entry which has entry to its * left which is not 1. Increment that entry. Then replace the * elements to its left with m,1,...,1, where m is the number that * makes the tuple sum to n. * * Example: the 4-partitions of 6, in order, are as follow, where * the 0 index is on the left: * *
   * 3,1,1,1.  i=1
   * 2,2,1,1.  i=1
   * 1,3,1,1.  i=2
   * 2,1,2,1   i=1
   * 1,2,2,1   i=2
   * 1,1,3,1   i=3
   * 2,1,1,2   i=1
   * 1,2,1,2   i=2
   * 1,1,2,2   i=3
   * 1,1,1,3
   * 
* * The same sequence where the 0-index is on the right is: *
   * 1,1,1,3
   * 1,1,2,2
   * 1,1,3,1
   * 1,2,1,2
   * 1,2,2,1
   * 1,3,1,1
   * 2,1,1,2
   * 2,1,2,1
   * 2,2,1,1
   * 3,1,1,1
   * 
*/ public static boolean nxt_partition_lo(int[] a) { int k = a.length, idx = 1; int sum = a[0]; while (idx < k) { sum += a[idx]; if (a[idx-1] > 1) break; idx++; } if (idx == k) return false; // sum is sum (i=0..idx) a[i]. this sum must be preserved. a[idx]++; for (int i=idx-1; i>=1; i--) a[i] = 1; // a[0] + (idx-1) + a[idx] = sum a[0] = 1 + sum - a[idx] - idx; return true; } public static boolean nxt_partition_hi(int[] a) { int k = a.length, idx = 1; int sum = a[k-1]; while (idx < k) { sum += a[k-idx-1]; if (a[k-idx] > 1) break; idx++; } if (idx == k) return false; // sum is sum (i=0..idx) a[k-i-1]. this sum must be preserved. a[k-idx-1]++; for (int i=idx-1; i>=1; i--) a[k-i-1] = 1; a[k-1] = 1 + sum - a[k-idx-1] - idx; return true; } /** * Increments a parition to the next representative partition * under the equivalence relation induced by S_k. The orientation * is 0-low. * * There is an equivalence relation on the set of k-partitions of * n induced by the symmetric group on 0..k-1. A unique * representative from each equivalence class is obtained by * requiring that the components of the tuple are non-increasing * as the index moves from 0 to k-1. I.e., (a[0],a[1],...,a[k-1]) * is a representative iff a[0]>=a[1]>=...>=a[k-1]. * * Algorithm: working from lowest to highest index, find the first * entry with idx>=1 such that if incremented, and the new value * stuttered all the way to the left (index 0), the resulting sum * will be <= n. Increment that entry, call the resulting value * of that entry b, and replace the elements to its left with * b,b,...,b,m, where m is the number that makes the components * sum to n. * * Example: the representative 4-partitions of 10, in order, are: * *
   * 7,1,1,1.  idx=1
   * 6,2,1,1.  idx=1
   * 5,3,1,1.  idx=1
   * 4,4,1,1.  idx=2
   * 5,2,2,1.  idx=1
   * 4,3,2,1.  idx=2
   * 3,3,3,1.  idx=3
   * 4,2,2,2.  idx=1
   * 3,3,2,2.
   * 
* * The same sequence, written with 0 on the right: *
   * 1,1,1,7.  idx=1
   * 1,1,2,6.  idx=1
   * 1,1,3,5.  idx=1
   * 1,1,4,4.  idx=2
   * 1,2,2,5.  idx=1
   * 1,2,3,4.  idx=2
   * 1,3,3,3.  idx=3
   * 2,2,2,4.  idx=1
   * 2,2,3,3
   * 
*/ public static boolean nxt_partition_sym_lo(int[] a) { int k = a.length, idx = 1; int sum = a[0]; while (idx < k) { sum += a[idx]; if ((idx+1)*(a[idx]+1) <= sum) break; idx++; } if (idx == k) return false; // sum is sum (i=0..idx) a[i]. this sum must be preserved. a[idx]++; for (int i=idx-1; i>=1; i--) a[i] = a[idx]; // a[0] + idx*a[idx] = sum a[0] = sum - idx*a[idx]; assert a[0]>=a[idx]; return true; } public static boolean nxt_partition_sym_hi(int[] a) { int k = a.length, idx = 1; int sum = a[k-1]; while (idx < k) { sum += a[k-idx-1]; if ((idx+1)*(a[k-idx-1]+1) <= sum) break; idx++; } if (idx == k) return false; a[k-idx-1]++; for (int i=idx-1; i>=1; i--) a[k-i-1] = a[k-idx-1]; a[k-1] = sum - idx*a[k-idx-1]; assert a[k-1]>=a[k-idx-1]; return true; } // Tests... public static void print(PrintStream out, int[] a) { if (a == null) out.print("null"); out.print("{"); for (int i=0; i0) out.print(","); out.print(a[i]); } out.print("}"); } public static void println(PrintStream out, int[] a) { print(out, a); out.println(); } public static void print(PrintStream out, int[][] a) { if (a == null) out.print("null"); out.print("{"); for (int i=0; i0) out.print(","); print(out, a[i]); } out.print("}"); } public static void println(PrintStream out, int[][] a) { print(out, a); out.println(); } private static void test_nxt_lex_lo(int n) { int[] a = new int[n]; int total = 1; out.println("Testing nxt_lex_lo:"); for (int i=0; i=k; int a[] = new int[k]; a[0] = n-k+1; for (int i=1; i=k; int a[] = new int[k]; int b[] = new int[k]; a[0] = n-k+1; for (int i=1; i=k; int a[] = new int[k]; a[0] = n-k+1; for (int i=1; i=k; int a[] = new int[k]; int b[] = new int[k]; a[0] = n-k+1; for (int i=1; i