Advertisement
lackofcheese

Creamsteak.java

Sep 10th, 2011
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.15 KB | None | 0 0
  1. import java.util.LinkedList;
  2.  
  3. /**
  4.  * Implements my algorithm for solving the Creamsteak problem, for generic nxn
  5.  * matrices.
  6.  *
  7.  * @author lackofcheese
  8.  */
  9. public class Creamsteak {
  10.     /**
  11.      * Represents a single row or column that needs to be processed when moving
  12.      * a mark.
  13.      *
  14.      * @author lackofcheese
  15.      */
  16.     private static class Task {
  17.         private boolean isRow;
  18.         private int i;
  19.         private int j;
  20.  
  21.         private Task(boolean isRow, int i, int j) {
  22.             this.isRow = isRow;
  23.             this.i = i;
  24.             this.j = j;
  25.         }
  26.     }
  27.  
  28.     /**
  29.      * Does the initial markup of largest elements in the columns and rows of a
  30.      * matrix.
  31.      *
  32.      * @param m
  33.      *            the matrix being solved.
  34.      * @param marks
  35.      *            The array of marks - should consist entirely of zeros
  36.      *            initially.
  37.      * @return An array containing the positions (as int[2]) of the elements.
  38.      */
  39.     private static int[][] init_marks(int[][] m, int[][] marks) {
  40.         int n = m.length;
  41.         int[][] collis = new int[n][2];
  42.         int nc = 0;
  43.  
  44.         // Mark the largest element in each row
  45.         for (int i = 0; i < n; i++) {
  46.             int maxVal = m[i][0];
  47.             int maxPos = 0;
  48.             for (int j = 1; j < n; j++) {
  49.                 if (m[i][j] > maxVal) {
  50.                     maxVal = m[i][j];
  51.                     maxPos = j;
  52.                 }
  53.             }
  54.             marks[i][maxPos]++;
  55.         }
  56.  
  57.         // Mark the largest element in each column, taking note of
  58.         // any double-marking.
  59.         for (int j = 0; j < n; j++) {
  60.             int maxVal = m[0][j];
  61.             int maxPos = 0;
  62.             for (int i = 1; i < n; i++) {
  63.                 if (m[i][j] > maxVal) {
  64.                     maxVal = m[i][j];
  65.                     maxPos = i;
  66.                 }
  67.             }
  68.             marks[maxPos][j]++;
  69.             if (marks[maxPos][j] > 1) {
  70.                 collis[nc][0] = maxPos;
  71.                 collis[nc][1] = j;
  72.                 nc++;
  73.             }
  74.         }
  75.  
  76.         // Create a new collision array with size equal to the number
  77.         // of collisions.
  78.         int[][] collis2 = new int[nc][2];
  79.         for (int i = 0; i < nc; i++) {
  80.             collis2[i][0] = collis[i][0];
  81.             collis2[i][1] = collis[i][1];
  82.         }
  83.         return collis2;
  84.     }
  85.  
  86.     /**
  87.      * Moves a mark from a double-marked position (i0, j0) to the next best
  88.      * available place in the matrix m.
  89.      *
  90.      * @param m
  91.      *            the matrix being solved.
  92.      * @param marks
  93.      *            the markup array for the matrix.
  94.      * @param i0
  95.      *            the row of the double-marked position.
  96.      * @param j0
  97.      *            the column of the double-marked position.
  98.      */
  99.     public static void move_mark(int[][] m, int[][] marks, int i0, int j0) {
  100.         int n = m.length;
  101.         // An array that tells us which elements have already been
  102.         // processed.
  103.         boolean[][] done = new boolean[n][n];
  104.         done[i0][j0] = true;
  105.  
  106.         // A queue that tells us which rows/columns still need to be
  107.         // processed.
  108.         LinkedList<Task> todo = new LinkedList<Task>();
  109.         todo.push(new Task(true, i0, j0));
  110.         todo.push(new Task(false, i0, j0));
  111.  
  112.         boolean hasMax = false;
  113.  
  114.         // The maximum value found so far, and its position.
  115.         int maxVal = 0;
  116.         int maxI = 0;
  117.         int maxJ = 0;
  118.  
  119.         // Process the queue until we are done.
  120.         while (!todo.isEmpty()) {
  121.             Task t = todo.pop();
  122.             boolean isRow = t.isRow;
  123.             int i = t.i;
  124.             int j = t.j;
  125.             // Loop through every element in the same row/column as (i,j)
  126.             for (int k = 0; k < n; k++) {
  127.                 int i1 = i;
  128.                 int j1 = j;
  129.                 if (isRow) {
  130.                     j1 = k;
  131.                 } else {
  132.                     i1 = k;
  133.                 }
  134.                 // (i1,j1) is the new value we are looking at.
  135.                 if ((i1 == i && j1 == j) || done[i1][j1]) {
  136.                     continue;
  137.                 }
  138.                 done[i1][j1] = true; // Ensure this value is not processed again
  139.                 // later.
  140.                 if (marks[i1][j1] > 0) {
  141.                     // If it's marked, we also need to process everything in the
  142.                     // same
  143.                     // column, if we're currently looking at a row, or the same
  144.                     // row
  145.                     // if we're currently looking at a column.
  146.                     todo.add(new Task(!isRow, i1, j1));
  147.                 } else {
  148.                     // Update our maximum if necessary.
  149.                     int newVal = m[i1][j1];
  150.                     if (!hasMax || newVal > maxVal) {
  151.                         hasMax = true;
  152.                         maxVal = newVal;
  153.                         maxI = i1;
  154.                         maxJ = j1;
  155.                     }
  156.                 }
  157.             }
  158.         }
  159.         // Move the mark.
  160.         marks[i0][j0]--;
  161.         marks[maxI][maxJ]++;
  162.     }
  163.  
  164.     /**
  165.      * Runs my algorithm for the creamsteak problem on the given matrix.
  166.      *
  167.      * @param m
  168.      *            A matrix; should be nxn with n > 1.
  169.      * @return The highest possible total meeting the Creamsteak criteria.
  170.      */
  171.     public static int creamsteak(int[][] m) {
  172.         int n = m.length;
  173.         for (int i = 0; i < n; i++) {
  174.             if (m[i].length != n) {
  175.                 throw new RuntimeException("Not square!");
  176.             }
  177.         }
  178.         if (n == 1) {
  179.             throw new RuntimeException("No solution for 1x1 case");
  180.         }
  181.  
  182.         // Mark maximums in the rows and columns, noting collisions.
  183.         int[][] marks = new int[n][n];
  184.         int[][] collis = init_marks(m, marks);
  185.  
  186.         // For each collision, move the mark to the best available place.
  187.         for (int i = 0; i < collis.length; i++) {
  188.             move_mark(m, marks, collis[i][0], collis[i][1]);
  189.         }
  190.  
  191.         // Calculate the total of the marked elements, and return it.
  192.         int total = 0;
  193.         for (int i = 0; i < n; i++) {
  194.             for (int j = 0; j < n; j++) {
  195.                 if (marks[i][j] == 0) {
  196.                 } else if (marks[i][j] == 1) {
  197.                     total += m[i][j];
  198.                 } else {
  199.                     throw new RuntimeException("I AM ERROR!");
  200.                 }
  201.             }
  202.         }
  203.         return total;
  204.     }
  205. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement