River Crossing
unknown
java
3 years ago
7.6 kB
20
Indexable
import java.util.*; /** * @author thucdx */ class MonkAndDevil { static class MonkAndDevilSolver { int numberOfEach; int maxOnBoat; static int INF = (int) 1e9; public MonkAndDevilSolver(int numberOfEach, int maxOnBoat) { this.numberOfEach = numberOfEach; this.maxOnBoat = maxOnBoat; } Map<GameState, GameState> prev = new HashMap<>(); Map<GameState, Integer> shortest = new HashMap<>(); public List<GameState> solve() { List<GameState> steps = new ArrayList<>(); // State at left side: n monks, n evil, boat is currently at this side Step first = new Step(numberOfEach, numberOfEach, true, 0); // Need to find the shortest path to Pair(0 - 0 monks, 0 - 0 devils, false - boat is at other side); Queue<Step> queue = new LinkedList<>(); shortest.put(first.state, first.step); queue.add(first); while (!queue.isEmpty()) { Step cur = queue.poll(); if (cur.getMonk() == 0 && cur.getDevil() == 0 && !cur.hasBoat()) { // Trace back list of state GameState curState = cur.state; do { steps.add(curState); curState = prev.get(curState); } while (prev.containsKey(curState)); steps.add(curState); // Need to reverse Collections.reverse(steps); return steps; } List<GameState> gameStates = moveFrom(cur.state); for (GameState nextState : gameStates) { if (shortest.getOrDefault(nextState, INF) > cur.step + 1) { shortest.put(nextState, cur.step + 1); Step nextStep = new Step(nextState, cur.step + 1); queue.add(nextStep); prev.put(nextStep.state, cur.state); } } } return steps; } static void print(List<GameState> states) { for (int i = 1; i < states.size(); i++) { GameState last = states.get(i - 1); int monk = Math.abs(states.get(i).monk - states.get(i - 1).monk); int devil = Math.abs(states.get(i).devil - states.get(i - 1).devil); String s = String.format("Move %d monk(s) and %d devil(s) from %s", monk, devil, last.hasBoat ? "left to right" : "right to left"); System.out.println(s); } } List<GameState> moveFrom(GameState current) { List<GameState> possibleState = new ArrayList<>(); if (current.hasBoat) { for (int devil = 0; devil <= maxOnBoat; devil++) { for (int monk = 0; monk <= maxOnBoat - devil; monk++) { if (devil == 0 && monk == 0) continue; if (monk != 0 && monk < devil) continue; int monkLeft = current.monk - monk; int devilLeft = current.devil - devil; if (monkLeft < 0 || devilLeft < 0) continue; if (monkLeft > 0 && monkLeft < devilLeft) continue; int monkOtherSide = (numberOfEach - current.monk) + monk; int devilOtherSide = (numberOfEach - current.devil) + devil; if (monkOtherSide > 0 && monkOtherSide < devilOtherSide) { continue; } if (monkOtherSide > numberOfEach || devilLeft > numberOfEach) { continue; } possibleState.add(new GameState(monkLeft, devilLeft, false)); } } } else { List<GameState> states = moveFrom(new GameState(numberOfEach - current.monk, numberOfEach - current.devil, true)); for (GameState state : states) { possibleState.add(new GameState(numberOfEach - state.monk, numberOfEach - state.devil, true)); } } return possibleState; } } static class Step implements Comparable<Step> { GameState state; int step; public Step(int first, int second, boolean hasBoat) { state = new GameState(first, second, hasBoat); step = 0; } public int getStep() { return step; } public int getMonk() { return state.monk; } public int getDevil() { return state.devil; } public boolean hasBoat() { return state.hasBoat; } public void setStep(int step) { this.step = step; } public Step(GameState other, int step) { this.state = other; this.step = step; } public Step(int first, int second, boolean hasBoat, int step) { state = new GameState(first, second, hasBoat); this.step = step; } @Override public String toString() { return "Step{" + "step=" + step + ", monk=" + state.monk + ", devil=" + state.devil + ", hasBoat=" + state.hasBoat + '}'; } @Override public int compareTo(Step o) { return step - o.step; } } static class GameState { int monk; // store number of monks int devil; // store number of devils boolean hasBoat; public GameState(int monk, int devil, boolean hasBoat) { this.monk = monk; this.devil = devil; this.hasBoat = hasBoat; } public GameState(GameState other) { this.monk = other.monk; this.devil = other.devil; this.hasBoat = other.hasBoat; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof GameState)) return false; GameState gameState = (GameState) o; if (monk != gameState.monk) return false; if (devil != gameState.devil) return false; return hasBoat == gameState.hasBoat; } @Override public int hashCode() { int result = monk; result = 31 * result + devil; result = 31 * result + (hasBoat ? 1 : 0); return result; } @Override public String toString() { return "Pair{" + "monk=" + monk + ", devil=" + devil + ", hasBoat=" + hasBoat + '}'; } } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(), m = sc.nextInt(); MonkAndDevilSolver solver = new MonkAndDevilSolver(n, m); List<GameState> states = solver.solve(); if (states.size() == 0) { System.out.println("Cannot move!!!"); } else { System.out.println("Finish in " + states.size() + " steps"); MonkAndDevilSolver.print(states); } } }
Editor is loading...