import java.util.*; /** * Homer's Broken Remote Control * * This program generates an optimal sequence to get from one channel * to another, assuming a remote control with some broken digit keys. * * For the UMD High School Programming Contest, 2008. * @author Dave Mount */ public class BrokenRemote { static final int MAX_POSSIBLE = 9999; // maximum possible channel static int maxChannel; // maximum channel number static int nWorkingDigits; // number of working digit keys static boolean[] isWorking; // true if i-th digit key works static int startChannel; // starting channel number static int targetChannel; // desired target channel number /** Main program. * * Reads inputs, invokes the algorithm, and outputs the answer. */ public static void main(String[] args) throws Exception { Scanner scanner = new Scanner( System.in ); // input remote state maxChannel = scanner.nextInt(); if (maxChannel > MAX_POSSIBLE) { System.out.println("Error: Maximum cannot exceed " + MAX_POSSIBLE); System.exit(0); } nWorkingDigits = scanner.nextInt(); isWorking = new boolean[10]; for (int i = 0; i < nWorkingDigits; i++) { int thisDigit = scanner.nextInt(); if (thisDigit < 0 || thisDigit > 9) { System.out.println("Error: Digit out of range"); System.exit(0); } isWorking[thisDigit] = true; } // echo state System.out.print("Max Channel: " + maxChannel); System.out.print(" Working Digits: "); for (int i = 0; i < 10; i++) { if (isWorking[i]) { System.out.print(i + " "); } } System.out.println(); // input start/target pairs while (scanner.hasNextInt()) { startChannel = scanner.nextInt(); targetChannel = scanner.nextInt(); if (startChannel < 1 || startChannel > maxChannel || targetChannel < 1 || targetChannel > maxChannel) { System.out.println("Error: Either start or target out of range"); System.exit(0); } // generate the optimal sequence String sequence = generateSequence(); // output final sequence System.out.println("Start: " + startChannel + " Target: " + targetChannel + " Sequence: " + makePrintable(sequence)); } } /** Convert sequence into printable form * * Sequences of '+' or '-' that are longer than 5 characters * printed as [99+] or [99-], where 99 is the repetition factor. * * As a side effect, we check that the sequence contains only valid * characters, and produce an error message if not. */ private static String makePrintable(String sequence) { final int MAX_REPEAT = 5; StringBuffer outputString = new StringBuffer(""); int n = sequence.length(); boolean isValid = true; int i = 0; while (i < n) { char ch = sequence.charAt(i); if (!Character.isDigit(ch) && ch != 'E' && ch != '+' && ch != '-') { isValid = false; } if (ch == '+' || ch == '-') { // check for repeats of + or - int j = i+1; while (j < n && sequence.charAt(j) == ch) j++; if (j-i > MAX_REPEAT) { outputString.append("[" + (j-i) + ch + "]"); } else { outputString.append(sequence.substring(i, j)); } i = j; } else { outputString.append(sequence.charAt(i)); i++; } } if (!isValid) { System.out.println("Error: Final sequence can only contain digits, 'E', '+', and '-'"); } return new String(outputString); } /** Generates the optimal remote control sequence * * This uses the global quantities maxChannel, startChannel, * targetChannel, nWorkingDigits, and isWorking[], defined above. * * The result is stored as a string, containing the digits '0'-'9' * along with 'E' (for Enter), '+' (up channel), or '-' (down * channel). */ private static String generateSequence() { /* ------------------- INSERT CODE HERE ---------------------*/ /* ===================SOLUTION STARTS HERE===================*/ /* ------------------------------------------------------------- * We solve the problem by computing two arrays: * * entChannel[]: An array of all the channels that can * be entered through the use of the (working) digit keys. * entSequence[]: The i-th entry is the string sequence used * to generate entChannel[i]. * * Because the maximum number of digits is not very large (at * most 9999), we just test whether every possible channel can * be entered using the working digit keys. To convert an integer * channel into a string we repeatedly mod by 10 to extract the * least significant digit and then divide by 10 to shift the * digits over. (We could have also used Integer.toString() to * do this.) * * For each entry of entChannel, we invoke the procedure * getUpDownSeq(), which returns a string of +, - to get from * this channel to the target, and return the shortest such * sequence. * * Warning: This code relies on the fact that the lowest legal * channel is 1. It doesn't work if 0 is a possible channel. * ------------------------------------------------------------- */ int entChannel[] = new int[MAX_POSSIBLE]; String entSequence[] = new String[MAX_POSSIBLE]; int nEnt = 0; // generate other channels for (int i = 1; i <= maxChannel; i++) { int channelDigits = i; boolean enterable = true; while (channelDigits > 0) { int digit = channelDigits % 10; // extract one digit if (!isWorking[digit]) { enterable = false; break; } channelDigits /= 10; // shift right one digit } if (enterable) { // can enter this channel entChannel[nEnt] = i; // add it to the list entSequence[nEnt] = new String(i + "E"); nEnt++; } } // initial sequence String minSequence = getUpDownSeq(startChannel, targetChannel); for (int i = 0; i < nEnt; i++) { // find length of all others String upDownSeq = new String(getUpDownSeq(entChannel[i], targetChannel)); if ((entSequence[i].length() + upDownSeq.length()) < minSequence.length()) { minSequence = entSequence[i] + upDownSeq; } } return minSequence; } /** Generates the sequence of '+' and '-' to get between channels. * * We use a StringBuffer rather than String, because it is a bit * more efficient for performing append operations. * */ private static String getUpDownSeq(int start, int target) { int upDistance; int downDistance; if (start <= target) { upDistance = target - start; downDistance = start + (maxChannel - target); } else { downDistance = start - target; upDistance = (maxChannel - start) + target; } StringBuffer sequence = new StringBuffer(""); if (upDistance <= downDistance) { for (int i = 0; i < upDistance; i++) { sequence.append('+'); } } else { for (int i = 0; i < downDistance; i++) { sequence.append('-'); } } return new String(sequence); /* ===================SOLUTION ENDS HERE=====================*/ /* -------------------- END OF INSERTION --------------------*/ } }