package com.interview.dynamic;
import java.util.HashMap;
import java.util.Map;
/**
* Date 11/23/2015
* @author Tushar Roy
*
* Given starting line and right barrier which is perpendicular to starting line. There are
* n gates at certain distinct distance from right barrier. Starting from start line how do you ski
* such that you can cover maximum number of gates. Changing direction is expensive so you can
* only do limited number of direction changes.
*
* Idea at every gate is to either select this gate or not select this gate. Another decision to make
* is to either change or not change direction at every gate(provided you have remainingDirectionChanges > 0).
* Do recursion and apply memoization to make it top down recursive solution.
*/
public class MaximizeSkiGates {
class Index {
int remainingChanges;
int current;
boolean isRight;
int prevItem;
Index(int remainingChanges, int current, boolean isRight, int prevItem) {
this.remainingChanges = remainingChanges;
this.current = current;
this.isRight = isRight;
this.prevItem = prevItem;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Index index = (Index) o;
if (remainingChanges != index.remainingChanges) return false;
if (current != index.current) return false;
if (isRight != index.isRight) return false;
return prevItem == index.prevItem;
}
@Override
public int hashCode() {
int result = remainingChanges;
result = 31 * result + current;
result = 31 * result + (isRight ? 1 : 0);
result = 31 * result + prevItem;
return result;
}
}
public int solution(int gates[], int totalDirectionChanges) {
Map<Index, Integer> dpMap = new HashMap<>();
return solution(gates, totalDirectionChanges, 0, false, -1, dpMap);
}
public int solution(int gates[], int remainingDirectionChanges, int current, boolean isRight, int prevItem, Map<Index, Integer> dpMap) {
if(current >= gates.length) {
return 0;
}
Index index = new Index(remainingDirectionChanges, current, isRight, prevItem);
if(dpMap.containsKey(index)) {
return dpMap.get(index);
}
int val1 = 0, val2 = 0;
//if current gate is picked.
if((isRight && gates[current] < prevItem) || (!isRight && gates[current] > prevItem)) {
//if we decide to continue in same direction.
val1 = 1 + solution(gates, remainingDirectionChanges, current + 1, isRight, gates[current], dpMap);
if(remainingDirectionChanges > 0) {
//if we flip direction. We can only do that if remainingDirectionChanges > 0
val2 = 1 + solution(gates, remainingDirectionChanges - 1, current + 1, !isRight, gates[current], dpMap);
}
}
//if current gate is not picked
int val3 = solution(gates, remainingDirectionChanges, current + 1, isRight, prevItem, dpMap);
//max of all 3 possibilities
int max = Math.max(Math.max(val1, val2), val3);
dpMap.put(index, max);
return max;
}
public static void main(String args[]) {
int input[] = {15, 13, 5, 7, 4, 10, 12, 8, 2, 11, 6, 9 , 3};
MaximizeSkiGates sg = new MaximizeSkiGates();
System.out.println(sg.solution(input, 2));
}
}