\usepackage{listings}
\usepackage[dvipdfm]{hyperref}
+\usepackage{color}
+\usepackage{amssymb}
+
+\definecolor{javared}{rgb}{0.6,0,0}
+\definecolor{javagreen}{rgb}{0.25,0.5,0.35}
+\definecolor{javapurple}{rgb}{0.5,0,0.35}
\lstset{
- basicstyle=\footnotesize,
+ basicstyle=\scriptsize,
breaklines=true,
numbers=left,
numberstyle=\tiny,
\subsection{Brute Force}
The first approach was to implement a brute force algorithm which calculates
every possible combination of pets and children and then takes the one with the
-highest value. This corresponds with the pseudocode specified in
-Listing~\ref{lst:brute_force}. The algorithm, due to calculating all the values
-has a minimal complexity of $n!$. This is because there are $n!$ permutations
-possible for $n$ children.
+highest value. This corresponds with the pseudocode specified together with a
+rough estimate of the complexity in Listing~\ref{lst:brute_force}. The
+algorithm, due to calculating all the values the algorithm has a complexity
+within $\mathcal{O}(n!)$.
+This is because there are $n!$ permutations possible for $n$ children.
\begin{lstlisting}[
caption={Brute Force approach},
label={lst:brute_force},
c1 - return maximum compatibility rating from list
\end{lstlisting}
-
-\subsection{Improvements}
+\subsection{Improved algorithm}
+The improved algorithm makes use of the fact that some rows only have very few
+positive compatibilities. If you handle the rows/columns in the order from
+little to lots of entries with compatibilites $1$ then a greedy approach will
+suffice. This corresponds with the pseudocode specified together with a rough
+estimate of the complexity in Listing~\ref{lst:improved}. The algorithm has a
+complexity lies in the $\mathcal{O}(nm)$ because the main loop repeats at
+maximum $n$ or $m$ times and the searching within the loop has a complexity of
+$n$ if the loop runs $m$ times and $m$ otherwise.
+\begin{lstlisting}[
+ caption={Improved approach},
+ label={lst:improved},
+ keywords={[3]while,create,put,return,find,remove}
+]
+n - create list result of length n and initialize with -1
+n+m - create list rows/columns that contain pairs of indices and sums of values
+nlgn - sort the rows and columns list on ascending sum
+(n+m)/2 - while there are still unused values in the lists
+c1 - pick the lowest value from the lists
+c2 - remove the value
+max(n, m) - find the lowest value in the corresponding antagonist
+c2 - remove the antagonist
+c3 - put the row/column pair in the results list
+c4 - return the results list
+\end{lstlisting}
\section{Conclusion}
-\end{document}
+\newpage
+\section{Appendices}
+\subsection{\textit{\href{http://www.java.com}{Java}} source}
+\lstinputlisting[
+ language=java,
+ keywordstyle=\color{javapurple}\bfseries,
+ stringstyle=\color{javared},
+ commentstyle=\color{javagreen},
+ stepnumber=2
+]{LubbersSolver.java}
+\end{document}
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Collections;
-import java.util.Random;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Comparator;
import java.util.AbstractMap.SimpleEntry;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
-import java.util.PriorityQueue;
-
+import java.util.LinkedList;
/**
- * Class that implements the pot problem solver.
- *
- * @author Mart Lubbers
+ * Class that implements the pet problem solver.
+ *
+ * @author Mart Lubbers, s4109503
*/
public class LubbersSolver implements IPetproblemSolver {
-
- public class Tuple implements Comparable<Tuple>
- {
- public int k;
- public int v;
-
- public Tuple(int k, int v)
- {
- this.k = k;
- this.v = v;
- }
-
- /**
- * Overrides compareTo so that the priorityqueue is ordered ascending
- *
- * @param a the entry to compare with
- * @return comparison value
- */
- @Override
- public int compareTo(Tuple a)
- {
- //note that the values are swapped, so that the sort will be reversed
- return Integer.compare(a.v, this.v);
- }
-
- @Override
- public String toString()
- {
- return k + ": " + v;
- }
- }
-
@Override
- public int[] solve(int n, int m, int[][] compatibility)
- {
+ public int[] solve(int n, int m, int[][] compatibility) {
+ // Create initial result list of of length n and fill with -1
int[] result = new int[n];
-
- // Set to -1 initially
- for (int i = 0; i < result.length; i++)
- result[i] = -1;
-
- // Sum rows and columns
- PriorityQueue<Tuple> row_sums = new PriorityQueue<Tuple>(n);
- PriorityQueue<Tuple> col_sums = new PriorityQueue<Tuple>(m);
-
- int[] running_row_sums = new int[n];
- int[] running_col_sums = new int[m];
-
- // Sum
- for (int j = 0; j < m; j++)
- {
- for (int i = 0; i < n; i++)
- {
- running_row_sums[i] += compatibility[i][j];
- running_col_sums[j] += compatibility[i][j];
+ Arrays.fill(result, -1);
+
+ // Create the lists that define the sums of the rows and columns
+ LinkedList<SimpleEntry<Integer, Integer>> rows = new LinkedList<SimpleEntry<Integer, Integer>>();
+ LinkedList<SimpleEntry<Integer, Integer>> cols = new LinkedList<SimpleEntry<Integer, Integer>>();
+
+ // Calculate the sums
+ int[] col_sums = new int[m];
+ for (int i = 0, sum = 0; i < n; i++) {
+ for (int j = 0; j < m; j++) {
+ sum += compatibility[i][j];
+ col_sums[j] += compatibility[i][j];
}
+ rows.add(new SimpleEntry<Integer, Integer>(i, sum));
}
-
- // Add running sums to queues
- for (int i = 0; i < running_row_sums.length; i++)
- row_sums.add(new Tuple(i, running_row_sums[i]));
-
- for (int i = 0; i < running_col_sums.length; i++)
- col_sums.add(new Tuple(i, running_col_sums[i]));
-
-
- // Select smallest sum (in rows/cols)
- // Get 1-indices for that sum's index
- // Select smallest from those indices
- while (!row_sums.isEmpty() && !col_sums.isEmpty()){
- Tuple lowestIndexRow = row_sums.peek();
- Tuple lowestIndexCol = col_sums.peek();
-
- boolean useRow = false;
-
- if (lowestIndexRow.v < lowestIndexCol.v)
- useRow = true;
-
- // Get 1-indices
- if (useRow)
- {
- row_sums.remove();
-
- // Get smallest
- int smallestValue = Integer.MAX_VALUE;
- Tuple smallestKey = null;
-
- for (Tuple e : col_sums)
- {
- if (e.v < smallestValue && compatibility[lowestIndexRow.k][e.k] == 1)
- {
- smallestKey = e;
- smallestValue = e.v;
+ for (int i = 0; i < m; i++) {
+ cols.add(new SimpleEntry<Integer, Integer>(i, col_sums[i]));
+ }
+ //Sort the lists so the rows and columns with the least amount of positive compatibilities
+ Comparator<SimpleEntry<Integer, Integer>> comp = new Comparator<SimpleEntry<Integer, Integer>>() {
+ @Override
+ public int compare(SimpleEntry<Integer, Integer> a, SimpleEntry<Integer, Integer> b) {
+ return a.getValue().compareTo(b.getValue());
+ }
+ };
+ Collections.sort(rows, comp);
+ Collections.sort(cols, comp);
+
+ /* 1. Find the row or column with the lowest sum(least available matches)
+ * Because the rows and columns are sorted on value the first item is the lowest
+ * 2. Find the match with the lowest sum and still positive compatibility for that row or column
+ * 3. Select smallest from those indices
+ */
+ SimpleEntry<Integer, Integer> MINIMUM = new SimpleEntry<Integer, Integer>(-1, Integer.MAX_VALUE);
+ while (!(rows.isEmpty() || cols.isEmpty())) {
+ //1. Find the row or column with the lowest sum(least available matches)
+ SimpleEntry<Integer, Integer> row_l = rows.peekFirst();
+ SimpleEntry<Integer, Integer> col_l = cols.peekFirst();
+
+ //2. The row is the lowest
+ if (row_l.getValue() < col_l.getValue()) {
+ //Remove the current lowest row sum
+ rows.remove(row_l);
+ //3. Find smallest column that has compatibility 1
+ SimpleEntry<Integer, Integer> smallest = MINIMUM;
+ for (SimpleEntry<Integer, Integer> e : cols) {
+ if (e.getValue() < smallest.getValue() && compatibility[row_l.getKey()][e.getKey()] == 1) {
+ smallest = e;
}
}
-
- // No candidates in this list, continue
- if (smallestKey == null)
+ //No pets left that have a positive compatibility
+ if (smallest.getKey() == -1) {
continue;
-
- int col_index = smallestKey.k;
- col_sums.remove(smallestKey);
-
- result[lowestIndexRow.k] = col_index;
- }
- else
- {
- col_sums.remove();
-
- // Get smallest
- int smallestValue = Integer.MAX_VALUE;
- Tuple smallestKey = null;
-
- for (Tuple e : row_sums)
- {
- if (e.v < smallestValue && compatibility[e.k][lowestIndexCol.k] == 1)
- {
- smallestKey = e;
- smallestValue = e.v;
+ }
+ cols.remove(smallest);
+ result[row_l.getKey()] = smallest.getKey();
+ //2. The column is the lowest
+ } else {
+ //Remove the current lowest column sum
+ cols.remove(col_l);
+ //3. Find smallest row that has compatibility 1
+ SimpleEntry<Integer, Integer> smallest = MINIMUM;
+ for (SimpleEntry<Integer, Integer> e : rows) {
+ if (e.getValue() < smallest.getValue() && compatibility[e.getKey()][col_l.getKey()] == 1) {
+ smallest = e;
}
}
-
- // No candidates in this list, continue
- if (smallestKey == null)
+ //No pets left that have a positive compatibility
+ if (smallest.getKey() == -1) {
continue;
-
- int row_index = smallestKey.k;
- row_sums.remove(smallestKey);
-
- result[row_index] = lowestIndexCol.k;
+ }
+ rows.remove(smallest);
+ result[smallest.getKey()] = col_l.getKey();
}
}
-
- int score = 0;
-
- for (int i = 0; i < result.length; i++)
- score += result[i] == -1 ? 0 : 1;
-
- System.out.println("Score: " + score);
-
return result;
}
-
}