Answers to textbook problems are not online.
Would A* be optimal with an admissible heuristic if we checked for goal states upon generation rather than expansion? Give an articulate, solid proof or counterexample, whichever is appropriate? Answer: No. Try it on this graph, where the only goal is D: A / \ 3/ \5 / \ (h=1)B C(h=6) \ / 9\ /6 \ / D(h=0, goal) First we expand a, generating B with f=3+1=4 and C with f=5+6=11. So we expand B next, which generates D. D has cost f=12+0=12. If we stop now, we return the path A-B-D, but this is not optimal. The optimal path goes through C. The real A* algorithm would expand C first.
import java.io.PrintStream; import java.util.ArrayList; import java.util.Random; public class MinConflictsQueensSolver { private static class Board { Random random = new Random(); /** * The row for each column, For example [3,7,0,4,6,1,5,2] represents * * <pre> * ..Q..... * .....Q.. * .......Q * Q....... * ...Q.... * ......Q. * ....Q... * .Q...... * </pre> */ int[] rows; /** * Creates a new n x n board and randomly fills it with one queen in each * column. */ Board(int n) { rows = new int[n]; scramble(); } /** * Randomly fills the board with one queen in each column. */ void scramble() { for (int i = 0, n = rows.length; i < n; i++) { rows[i] = i; } for (int i = 0, n = rows.length; i < n; i++) { int j = random.nextInt(n); int rowToSwap = rows[i]; rows[i] = rows[j]; rows[j] = rowToSwap; } } /** * Returns the number of queens that conflict with (row,col), not counting the * queen in column col. */ int conflicts(int row, int col) { int count = 0; for (int c = 0; c < rows.length; c++) { if (c == col) continue; int r = rows[c]; if (r == row || Math.abs(r - row) == Math.abs(c - col)) count++; } return count; } /** * Fills the board with a legal arrangement of queens. */ void solve() { int moves = 0; // This would be a lot faster if we used arrays of ints instead. ArrayList<Integer> candidates = new ArrayList<Integer>(); while (true) { // Find nastiest queen int maxConflicts = 0; candidates.clear(); for (int c = 0; c < rows.length; c++) { int conflicts = conflicts(rows[c], c); if (conflicts == maxConflicts) { candidates.add(c); } else if (conflicts > maxConflicts) { maxConflicts = conflicts; candidates.clear(); candidates.add(c); } } if (maxConflicts == 0) { // Checked *every* queen and found no conflicts return; } // Pick a random queen from those that had the most conflicts int worstQueenColumn = candidates.get(random.nextInt(candidates.size())); // Move her to the place with the least conflicts. int minConflicts = rows.length; candidates.clear(); for (int r = 0; r < rows.length; r++) { int conflicts = conflicts(r, worstQueenColumn); if (conflicts == minConflicts) { candidates.add(r); } else if (conflicts < minConflicts) { minConflicts = conflicts; candidates.clear(); candidates.add(r); } } if (!candidates.isEmpty()) { rows[worstQueenColumn] = candidates.get(random.nextInt(candidates.size())); } moves++; if (moves == rows.length * 2) { // Trying too long... start over. scramble(); moves = 0; } } } /** * Prints the board, crudely, to a print stream. */ void print(PrintStream stream) { for (int r = 0; r < rows.length; r++) { for (int c = 0; c < rows.length; c++) { stream.print(rows[c] == r ? 'Q' : '.'); } stream.println(); } } } /** * Runs the application. */ public static void main(String[] args) { Board board = new Board(500); long start = System.currentTimeMillis(); board.solve(); long stop = System.currentTimeMillis(); System.out.println("Found in " + ((double) (stop - start)) / 1000 + "s."); board.print(System.out); } }
The traveling salesperson problem can be solved with hill climbing as follows: