├── LICENSE ├── Makefile ├── README.md ├── pc.nw ├── pc.pdf └── src ├── Chapter1 ├── AustralianVoting.java ├── CheckTheCheck.java ├── Collatz.java ├── GraphicalEditor.java ├── Interpreter.java ├── LCDisplay.java ├── Minesweeper.java └── TheTrip.java ├── Chapter10 ├── FireStations.java ├── Freckles.java ├── Railroads.java ├── TheGrandDinner.java ├── TheNecklace.java ├── TheProblemWithTheProblemSetter.java ├── TouristGuide.java └── War.java ├── Chapter11 ├── CuttingSticks.java ├── DistinctSubsequences.java ├── FerryLoading.java ├── IsBiggerSmarter.java ├── UnidirectionalTSP.java └── WeightsAndMeasures.java ├── Chapter12 ├── Airlines.java ├── AntOnAChessboard.java ├── BeeMaja.java ├── DermubaTriangle.java ├── Robbery.java ├── SqrRectsCubesBoxes.java ├── Star.java └── TheMonocycle.java ├── Chapter13 ├── BirthdayCake.java ├── ChocolateChipCookies.java ├── DogAndGopher.java ├── RopeCrisisInRopeland.java ├── TheKnightsOfTheRoundTable.java └── TheLargestSmallestBox.java ├── Chapter2 ├── ContestScoreboard.java ├── CryptKicker.java ├── ErdosNumbers.java ├── Hartals.java ├── JollyJumpers.java ├── PokerHands.java ├── StackEmUp.java └── Yahtzee.java ├── Chapter3 ├── AutomatedJudgeScript.java ├── CommonPermutation.java ├── CryptKickerII.java ├── Doublets.java ├── FileFragmentation.java ├── Fmt.java ├── WERTYU.java └── WheresWaldorf.java ├── Chapter4 ├── Bridge.java ├── CDVII.java ├── FootballAkaSoccer.java ├── LongestNap.java ├── ShellSort.java ├── ShoemakersProblem.java ├── StacksOfFlapjacks.java └── VitosFamily.java ├── Chapter5 ├── MultiplicationGame.java ├── Ones.java ├── PairsumoniousNumbers.java ├── PolynomialCoefficients.java ├── PrimaryArithmetic.java ├── ReverseAndAdd.java ├── TheArcheologistsDilemma.java └── TheSternBrocotNumberSystem.java ├── Chapter6 ├── CompleteTreeLabeling.java ├── Counting.java ├── Expressions.java ├── HowManyFibs.java ├── HowManyPiecesOfLand.java ├── SelfDescribingSequence.java ├── Steps.java └── ThePriestMathematician.java ├── Chapter7 ├── CarmichaelNumbers.java ├── EuclidProblem.java ├── Factovisors.java ├── LightMoreLight.java ├── Marbles.java ├── SmithNumbers.java └── SummationOfFourPrimes.java ├── Chapter8 ├── BiggerSquarePleaseMetaProgram.java ├── BiggerSquarePleaseOffline.java ├── BiggerSquarePleaseOffline.out ├── ColoursHash.java ├── GardenOfEden.java ├── LittleBishops.java ├── Queue.java ├── ServicingStations.java ├── The15PuzzleProblem.java └── TugOfWar.java └── Chapter9 ├── Bicoloring.java ├── EditStepLadders.java ├── FromDuskTillDawn.java ├── HanoiTowerTroublesAgain.java ├── PlayingWithWheels.java ├── SlashMaze.java ├── TheTouristGuide.java └── TowerOfCubes.java /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Roman Valiusenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvprg/pc/8f5740348c57cea3c6cb8a236165d6c702a729ba/pc.pdf -------------------------------------------------------------------------------- /src/Chapter1/AustralianVoting.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayDeque; 8 | import java.util.ArrayList; 9 | import java.util.Deque; 10 | import java.util.List; 11 | import static java.util.stream.Collectors.groupingBy; 12 | import static java.util.stream.IntStream.range; 13 | import java.util.Map; 14 | 15 | class AustralianVoting { 16 | private static final String EMPTY = ""; 17 | private static final BufferedReader reader = 18 | new BufferedReader(new InputStreamReader(System.in)); 19 | 20 | private static List elect(List candidates, 21 | List> ballots) { 22 | final int majority = ballots.size() / 2 + 1; 23 | final int[] counter = new int[candidates.size()]; 24 | ballots.stream().map(Deque::peek).forEach(x -> counter[x]++); 25 | while (true) { 26 | Map> result = range(0, candidates.size()).boxed() 27 | .filter(x -> counter[x] >= 0).collect(groupingBy(i -> counter[i], toList())); 28 | int max = result.keySet().stream().max(Integer::compareTo).get(); 29 | int min = result.keySet().stream().min(Integer::compareTo).get(); 30 | if (max >= majority || max == min) { 31 | return result.get(max).stream().map(x -> candidates.get(x)).collect(toList()); 32 | } 33 | List eliminated = result.get(min); 34 | eliminated.forEach(x -> counter[x] = -1); 35 | ballots.forEach(b -> { 36 | int first = b.peek(); 37 | eliminated.forEach(x -> b.remove(x)); 38 | counter[b.peek()] += (first != b.peek()) ? 1 : 0; 39 | }); 40 | } 41 | } 42 | 43 | public static void main(String[] args) throws IOException { 44 | int n = Integer.valueOf(reader.readLine().trim()); 45 | reader.readLine(); 46 | for (int i = 0; i < n; ++i) { 47 | int count = Integer.valueOf(reader.readLine().trim()); 48 | List candidates = reader.lines().limit(count).collect(toList()); 49 | List> ballots = new ArrayList>(); 50 | String currentLine = EMPTY; 51 | while ((currentLine = reader.readLine()) != null && 52 | !currentLine.equalsIgnoreCase(EMPTY)) { 53 | ballots.add(new ArrayDeque(stream(currentLine.trim().split(" ")) 54 | .filter(x -> !x.equals(EMPTY)) 55 | .map(Integer::parseInt).map(x -> x - 1).collect(toList()))); 56 | } 57 | elect(candidates, ballots).forEach(System.out::println); 58 | if (i < n - 1) { 59 | System.out.println(); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Chapter1/Collatz.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.HashMap; 4 | import java.util.ArrayDeque; 5 | import java.util.Deque; 6 | import java.util.stream.IntStream; 7 | 8 | class Collatz { 9 | private static int MAX = 1000000; 10 | private int[] lengths = new int[MAX]; 11 | private static final BufferedReader reader = 12 | new BufferedReader(new InputStreamReader(System.in)); 13 | int get(long index, HashMap surplus) { 14 | return (index < MAX) ? lengths[(int) index] : 15 | (surplus.containsKey(index) ? surplus.get(index) : 0); 16 | } 17 | 18 | void set(long index, int value, HashMap surplus) { 19 | if (index < MAX) { 20 | lengths[(int) index] = value; 21 | } else { 22 | surplus.put(index, value); 23 | } 24 | } 25 | 26 | Collatz() { 27 | final HashMap surplus = new HashMap(); 28 | lengths[1] = 1; 29 | for (long i = 2; i < MAX; ++i) { 30 | final Deque stack = new ArrayDeque(); 31 | long n = i; 32 | int len = 2; 33 | while (n != 1) { 34 | stack.push(n); 35 | int prev = get(n, surplus); 36 | if (prev > 0) { 37 | len = prev; 38 | break; 39 | } 40 | n = n % 2 == 0 ? n / 2 : n * 3 + 1; 41 | } 42 | while (!stack.isEmpty()) { 43 | set(stack.pop(), len++, surplus); 44 | } 45 | } 46 | } 47 | 48 | public static void main(String[] args) { 49 | Collatz s = new Collatz(); 50 | String input; 51 | while ((input = reader.readLine()) != null && 52 | !input.trim().equalsIgnoreCase("")) { 53 | List str = Arrays.stream(input.trim().split(" ")) 54 | .filter(x -> !x.equals("")).collect(Collectors.toList()); 55 | int x[] = new int[] { Integer.parseInt(str.get(0)), 56 | Integer.parseInt(str.get(1)) }; 57 | System.out.println(x[0] + " " + x[1] + " " + 58 | IntStream.rangeClosed(Math.min(x[0], x[1]), Math.max(x[0], 59 | x[1])).map(v -> s.lengths[v]).max().getAsInt()); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Chapter1/Interpreter.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | class Interpreter { 8 | private static final BufferedReader reader = 9 | new BufferedReader(new InputStreamReader(System.in)); 10 | 11 | private static int interpret(List input) { 12 | int[] reg = new int[10]; 13 | int[] ram = new int[1000]; 14 | for (int i = 0; i < input.size(); ++i) { 15 | ram[i] = input.get(i); 16 | } 17 | int pc = 0; 18 | int r = 0; 19 | while (ram[pc] != 100) { 20 | int op = ram[pc]; 21 | int c = (op / 100) % 10; 22 | pc = (pc + 1) % 1000; 23 | r++; 24 | switch (c) { 25 | case 2: 26 | reg[(op / 10) % 10] = op % 10; 27 | break; 28 | case 3: 29 | reg[(op / 10) % 10] = (reg[(op / 10) % 10] + (op % 10)) % 1000; 30 | break; 31 | case 4: 32 | reg[(op / 10) % 10] = (reg[(op / 10) % 10] * (op % 10)) % 1000; 33 | break; 34 | case 5: 35 | reg[(op / 10) % 10] = reg[op % 10]; 36 | break; 37 | case 6: 38 | reg[(op / 10) % 10] = (reg[(op / 10) % 10] + reg[op % 10]) % 1000; 39 | break; 40 | case 7: 41 | reg[(op / 10) % 10] = (reg[(op / 10) % 10] * reg[op % 10]) % 1000; 42 | break; 43 | case 8: 44 | reg[(op / 10) % 10] = ram[reg[op % 10]]; 45 | break; 46 | case 9: 47 | ram[reg[op % 10]] = reg[(op / 10) % 10]; 48 | break; 49 | case 0: 50 | if (reg[op % 10] != 0) { 51 | pc = reg[(op / 10) % 10]; 52 | } 53 | break; 54 | } 55 | } 56 | 57 | return r + 1; 58 | } 59 | 60 | public static void main(String[] args) throws IOException { 61 | int n = Integer.valueOf(reader.readLine().trim()); 62 | reader.readLine(); 63 | String currentLine; 64 | for (int i = 0; i < n; ++i) { 65 | List input = new ArrayList(); 66 | while ((currentLine = reader.readLine()) != null && 67 | !currentLine.trim().equalsIgnoreCase("")) { 68 | input.add(Integer.parseInt(currentLine.trim())); 69 | } 70 | System.out.println(interpret(input)); 71 | if (i < n - 1) { 72 | System.out.println(); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Chapter1/LCDisplay.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.stream.Stream; 5 | import static java.lang.String.join; 6 | import static java.util.Collections.nCopies; 7 | import java.util.function.Function; 8 | import static java.util.stream.Collectors.joining; 9 | import java.util.function.BiFunction; 10 | import static java.util.stream.Collectors.toList; 11 | import static java.util.stream.Stream.of; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import static java.util.stream.IntStream.range; 15 | import static java.util.stream.IntStream.rangeClosed; 16 | 17 | class LCDisplay { 18 | private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 19 | private static final String INPUT_END = "0 0"; 20 | private static final String EMPTY = ""; 21 | private static final String SPACE = " "; 22 | private static final byte[] pattern = new byte[] { 23 | 0x77, 0x03, 0x5d, 0x1f, 0x2b, 0x3e, 0x7e, 0x07, 0x7f, 0x3f 24 | }; 25 | 26 | private static List segments(final String digits, final int scale) { 27 | Function g = x -> join(EMPTY, nCopies(scale, x)); 28 | BiFunction, Byte, Stream> h = 29 | (m, x) -> m.map(mask -> (x & mask) > 0 ? "|" : SPACE); 30 | BiFunction, Byte, String> k = 31 | (m, d) -> SPACE + h.apply(m, d).map(x -> g.apply(x)).collect(joining(SPACE)) + SPACE; 32 | final int digitHeight = scale * 2 + 3; 33 | Function> f = x -> Arrays.asList( 34 | of(k.apply(of(0x40, 0x20), x)), 35 | nCopies(scale, h.apply(of(0x10, 0x08, 0x04), x) 36 | .collect(joining(g.apply(SPACE))).replace('|', '-')).stream(), 37 | of(k.apply(of(0x02, 0x01), x)), 38 | of(join(EMPTY, nCopies(digitHeight, SPACE)))) 39 | .stream().reduce(Stream::concat).get(); 40 | 41 | List segments = digits.chars().map(x -> x - '0').boxed() 42 | .flatMap(x -> f.apply(pattern[x])).collect(toList()); 43 | 44 | return rangeClosed(1, digitHeight).boxed() 45 | .map(j -> digitHeight - j).map(j -> range(0, segments.size() - 1).boxed() 46 | .map(i -> Character.toString(segments.get(i).charAt(j))).collect(joining())).collect(toList()); 47 | } 48 | 49 | public static void main(String[] args) throws IOException { 50 | String currentLine = INPUT_END; 51 | while ((currentLine = reader.readLine()) != null && 52 | !currentLine.trim().equalsIgnoreCase(INPUT_END)) { 53 | List input = Arrays.stream(currentLine.trim().split(SPACE)) 54 | .filter(x -> !x.equals("")).collect(Collectors.toList()); 55 | segments(input.get(1), Integer.valueOf(input.get(0))).stream() 56 | .forEach(System.out::println); 57 | System.out.println(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Chapter1/Minesweeper.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import static java.util.Arrays.stream; 5 | import static java.util.stream.Collectors.joining; 6 | import static java.util.stream.Collectors.toList; 7 | import static java.util.stream.IntStream.range; 8 | import java.util.List; 9 | import java.util.function.IntBinaryOperator; 10 | import java.util.function.IntUnaryOperator; 11 | 12 | class Minesweeper { 13 | private static final BufferedReader reader = 14 | new BufferedReader(new InputStreamReader(System.in)); 15 | private static final String SPACE = " "; 16 | private static final int[][] p = new int[][] { 17 | { -1, -1 }, { 0, -1 }, { 1, -1 }, { -1, 0 }, 18 | { 1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 } 19 | }; 20 | 21 | public static void main(String[] args) throws IOException { 22 | int lineNum = 0; 23 | String currentLine = INPUT_END; 24 | while ((currentLine = reader.readLine()) != null) { 25 | if (currentLine.equalsIgnoreCase("")) { 26 | continue; 27 | } 28 | List nm = stream(currentLine.split(SPACE)) 29 | .filter(x -> !x.equals("")).map(Integer::parseInt).collect(toList());; 30 | int n = nm.get(0); 31 | int m = nm.get(1); 32 | if (n == 0 && m == 0) { 33 | break; 34 | } 35 | 36 | final int[] field = reader.lines().limit(n) 37 | .collect(joining()).chars().map(x -> x == '*' ? -1 : 0).toArray(); 38 | 39 | final IntBinaryOperator mine = 40 | (x, y) -> (x < 0 || x > (n - 1) || y < 0 || y > (m - 1)) ? 0 : field[x * m + y]; 41 | 42 | final IntUnaryOperator count = (i) -> range(0, p.length) 43 | .map(j -> Math.abs(mine.applyAsInt(i / m + p[j][0], i % m + p[j][1]))).sum(); 44 | 45 | int[] result = range(0, field.length) 46 | .map(x -> field[x] >= 0 ? count.applyAsInt(x) : field[x]).toArray(); 47 | 48 | if (lineNum > 0) { 49 | System.out.println(); 50 | } 51 | 52 | System.out.println("Field #" + (++lineNum) + ":"); 53 | for (int i = 0; i < n; ++i) { 54 | for (int j = 0; j < m; ++j) { 55 | System.out.print(result[i * m + j] == -1 ? "*" : result[i * m + j]); 56 | } 57 | System.out.println(); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Chapter1/TheTrip.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.lang.Math.abs; 3 | import static java.util.stream.Collectors.partitioningBy; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.math.BigDecimal; 10 | 11 | class TheTrip { 12 | static long calculate(long[] values) { 13 | if (values.length == 1) 14 | return 0; 15 | long total = stream(values).sum(); 16 | long quotient = total / values.length; 17 | long reminder = total % values.length; 18 | Map> diff = 19 | stream(values).map(x -> x - quotient).boxed().collect(partitioningBy(x -> x > 0)); 20 | long sum = abs(diff.get(false).stream().reduce(Long::sum).get()); 21 | long len = diff.get(true).size(); 22 | reminder = len <= reminder ? reminder - len : 0; 23 | return sum + reminder; 24 | } 25 | 26 | public static void main(String[] args) throws IOException { 27 | BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); 28 | int n = 0; 29 | while ((n = Integer.parseInt(r.readLine().trim())) > 0) { 30 | long[] values = r.lines().limit(n).map(x -> x.replaceAll("\\.", 31 | "").trim()).mapToLong(Long::parseLong).toArray(); 32 | System.out.println("$" + BigDecimal.valueOf(calculate(values), 2)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Chapter10/Freckles.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.text.DecimalFormat; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class Freckles { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | 15 | static class Edge { 16 | final double[] src; 17 | final double[] dst; 18 | final double distance; 19 | 20 | public Edge(double[] src, double[] dst) { 21 | super(); 22 | this.src = src; 23 | this.dst = dst; 24 | double xx = Math.abs(src[0] - dst[0]); 25 | double yy = Math.abs(src[1] - dst[1]); 26 | this.distance = Math.sqrt(xx * xx + yy * yy); 27 | } 28 | } 29 | 30 | private static Edge min(List tree, List nodes) { 31 | Edge min = null; 32 | for (double[] n : nodes) { 33 | for (double[] t : tree) { 34 | Edge edge = new Edge(t, n); 35 | if (min != null && edge.distance < min.distance || 36 | min == null) { 37 | min = edge; 38 | } 39 | } 40 | } 41 | return min; 42 | } 43 | 44 | private static double mst(List nodes) { 45 | double total = 0; 46 | List tree = new ArrayList<>(); 47 | tree.add(nodes.remove(0)); 48 | while (!nodes.isEmpty()) { 49 | Edge edge = min(tree, nodes); 50 | total += edge.distance; 51 | tree.add(edge.dst); 52 | nodes.remove(edge.dst); 53 | } 54 | return total; 55 | } 56 | 57 | public static void main(String[] args) throws IOException { 58 | int n = Integer.parseInt(reader.readLine().trim()); 59 | DecimalFormat format = new DecimalFormat("#0.00"); 60 | reader.readLine(); 61 | for (int i = 0; i < n; ++i) { 62 | int m = Integer.parseInt(reader.readLine().trim()); 63 | List nodes = new ArrayList<>(); 64 | for (int j = 0; j < m; ++j) { 65 | List tuple = stream(reader.readLine().trim().split(" ")) 66 | .filter(x -> !x.equals("")) 67 | .map(Double::parseDouble) 68 | .collect(toList()); 69 | nodes.add(new double[] { tuple.get(0), tuple.get(1) }); 70 | } 71 | System.out.println(format.format(mst(nodes))); 72 | if (i < n - 1) { 73 | System.out.println(); 74 | } 75 | reader.readLine(); 76 | } 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/Chapter10/Railroads.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.stream.Collectors; 11 | 12 | public class Railroads { 13 | private static final BufferedReader reader = new BufferedReader( 14 | new InputStreamReader(System.in)); 15 | 16 | private static final int MAX_TIME = 2360; 17 | private static final int DEP_TIME = 0; 18 | private static final int DEP_STATION = 1; 19 | private static final int ARR_TIME = 2; 20 | private static final int ARR_STATION = 3; 21 | 22 | private static int[] solve(int m, List trains, int source, 23 | int startTime, int destination) { 24 | Map times = new HashMap<>(); 25 | 26 | for (int j = 0; j < m; ++j) { 27 | int[] tab = new int[MAX_TIME]; 28 | Arrays.fill(tab, -1); 29 | times.put(j, tab); 30 | } 31 | 32 | Collections.sort(trains, 33 | (x, y) -> x[DEP_TIME] != y[DEP_TIME] ? x[DEP_TIME] - y[DEP_TIME] 34 | : x[ARR_TIME] - x[ARR_TIME]); 35 | 36 | for (int[] t : trains) { 37 | int[] tab = times.get(t[ARR_STATION]); 38 | if (t[DEP_STATION] == source && t[DEP_TIME] >= startTime) { 39 | for (int j = t[ARR_TIME]; j < tab.length; ++j) { 40 | tab[j] = Math.max(tab[j], t[DEP_TIME]); 41 | } 42 | } else if (times.get(t[DEP_STATION])[t[DEP_TIME]] >= 0) { 43 | for (int j = t[ARR_TIME]; j < tab.length; ++j) { 44 | tab[j] = Math.max(tab[j], 45 | times.get(t[DEP_STATION])[t[DEP_TIME]]); 46 | } 47 | } 48 | } 49 | 50 | for (int j = 0; j < MAX_TIME; ++j) { 51 | if (times.get(destination)[j] > 0) { 52 | return new int[] { times.get(destination)[j], j }; 53 | } 54 | } 55 | 56 | return null; 57 | } 58 | 59 | public static void main(String[] args) throws IOException { 60 | int n = Integer.parseInt(reader.readLine().trim()); 61 | for (int i = 0; i < n; ++i) { 62 | int m = Integer.parseInt(reader.readLine().trim()); 63 | Map names = new HashMap<>(); 64 | for (int j = 0; j < m; ++j) { 65 | names.put(reader.readLine().trim(), j); 66 | } 67 | 68 | List trains = new ArrayList<>(); 69 | int trainsCount = Integer.parseInt(reader.readLine().trim()); 70 | for (int j = 0; j < trainsCount; ++j) { 71 | int stops = Integer.parseInt(reader.readLine().trim()); 72 | int[] prev = null; 73 | for (int k = 0; k < stops; ++k) { 74 | List stop = Arrays 75 | .stream(reader.readLine().trim().split(" ")) 76 | .filter(x -> !x.isEmpty()) 77 | .collect(Collectors.toList()); 78 | if (prev != null) { 79 | trains.add(new int[] { 80 | prev[0], prev[1], 81 | Integer.parseInt(stop.get(0)), 82 | names.get(stop.get(1)) }); 83 | } 84 | prev = new int[] { Integer.parseInt(stop.get(0)), 85 | names.get(stop.get(1)) }; 86 | } 87 | } 88 | 89 | int startTime = Integer.parseInt(reader.readLine().trim()); 90 | String sourceStr = reader.readLine().trim(); 91 | int source = names.get(sourceStr); 92 | String destinationStr = reader.readLine().trim(); 93 | int destination = names.get(destinationStr); 94 | 95 | int[] result = solve(m, trains, source, startTime, destination); 96 | 97 | System.out.println("Scenario " + (i + 1)); 98 | if (result != null) { 99 | System.out.printf("Departure %04d %s\n", result[0], sourceStr); 100 | System.out.printf("Arrival %04d %s\n", result[1], 101 | destinationStr); 102 | } else { 103 | System.out.println("No connection"); 104 | } 105 | System.out.println(); 106 | } 107 | } 108 | 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/Chapter10/TheGrandDinner.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | import java.util.Scanner; 4 | import java.util.stream.Collectors; 5 | 6 | public class TheGrandDinner { 7 | static class Tuple { 8 | final int v1; 9 | int v2; 10 | 11 | public Tuple(int v1, int v2) { 12 | this.v1 = v1; 13 | this.v2 = v2; 14 | } 15 | } 16 | 17 | public static List> solve(List teams, List tables) { 18 | List> solution = new ArrayList<>(); 19 | teams.forEach(x -> solution.add(new ArrayList<>())); 20 | teams.sort((x, y) -> Integer.compare(y.v2, x.v2)); 21 | for (int i = 0; i < teams.size(); ++i) { 22 | tables.sort((x, y) -> Integer.compare(y.v2, x.v2)); 23 | for (int j = 0; j < tables.size() && teams.get(i).v2 > 0; ++j) { 24 | solution.get(teams.get(i).v1 - 1).add(tables.get(j).v1); 25 | tables.get(j).v2--; 26 | teams.get(i).v2--; 27 | if (tables.get(j).v2 < 0) { 28 | return null; 29 | } 30 | } 31 | if (teams.get(i).v2 > 0) { 32 | return null; 33 | } 34 | } 35 | return solution; 36 | } 37 | 38 | public static void main(String[] args) { 39 | Scanner s = new Scanner(System.in); 40 | int n = 0; 41 | int m = 0; 42 | 43 | while (true) { 44 | m = s.nextInt(); 45 | n = s.nextInt(); 46 | if (m == 0 && n == 0) { 47 | break; 48 | } 49 | List teams = new ArrayList<>(); 50 | List tables = new ArrayList<>(); 51 | for (int i = 0; i < m; ++i) { 52 | teams.add(new Tuple(i + 1, s.nextInt())); 53 | } 54 | for (int i = 0; i < n; ++i) { 55 | tables.add(new Tuple(i + 1, s.nextInt())); 56 | } 57 | 58 | List> solution = solve(teams, tables); 59 | if (solution != null) { 60 | System.out.println(1); 61 | for (int i = 0; i < m; i++) { 62 | System.out.println(solution.get(i) 63 | .stream().map(String::valueOf) 64 | .collect(Collectors.joining(" "))); 65 | } 66 | } else { 67 | System.out.println(0); 68 | } 69 | } 70 | } 71 | 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/Chapter10/TheNecklace.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class TheNecklace { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | private static final int MAX_COL = 51; 15 | private final List> nodes; 16 | private final List> traversed = new ArrayList<>(); 17 | private final List path = new ArrayList<>(); 18 | 19 | private TheNecklace(List> nodes) { 20 | this.nodes = nodes; 21 | for (int i = 0; i < MAX_COL; ++i) { 22 | traversed.add(new ArrayList<>()); 23 | } 24 | 25 | boolean eulerian = true; 26 | int src = -1; 27 | for (int i = 0; i < nodes.size(); ++i) { 28 | List node = nodes.get(i); 29 | if (node.size() % 2 != 0) { 30 | eulerian = false; 31 | break; 32 | } 33 | for (int j = 0; j < node.size(); ++j) { 34 | traversed.get(i).add(false); 35 | } 36 | if (src == -1 && node.size() > 0) { 37 | src = i; 38 | } 39 | } 40 | 41 | if (eulerian) { 42 | traverse(src, 0); 43 | } 44 | } 45 | 46 | private void traverse(int src, int pos) { 47 | for (int i = 0; i < nodes.get(src).size(); ++i) { 48 | if (traversed.get(src).get(i)) { 49 | continue; 50 | } 51 | traversed.get(src).set(i, true); 52 | int dst = nodes.get(src).get(i); 53 | for (int j = 0; j < nodes.get(dst).size(); ++j) { 54 | if (nodes.get(dst).get(j) == src && 55 | !traversed.get(dst).get(j)) { 56 | traversed.get(dst).set(j, true); 57 | break; 58 | } 59 | } 60 | path.add(pos, new int[] { src, dst }); 61 | traverse(dst, pos + 1); 62 | } 63 | } 64 | 65 | public static void main(String[] args) throws IOException { 66 | int n = Integer.parseInt(reader.readLine().trim()); 67 | for (int i = 0; i < n; ++i) { 68 | int m = Integer.parseInt(reader.readLine().trim()); 69 | List> nodes = new ArrayList<>(); 70 | for (int j = 0; j < MAX_COL; ++j) { 71 | nodes.add(new ArrayList<>()); 72 | } 73 | for (int j = 0; j < m; ++j) { 74 | List node = stream( 75 | reader.readLine().trim().split(" ")) 76 | .filter(x -> !x.equals("")) 77 | .map(Integer::parseInt) 78 | .collect(toList()); 79 | nodes.get(node.get(0)).add(node.get(1)); 80 | nodes.get(node.get(1)).add(node.get(0)); 81 | } 82 | TheNecklace necklace = new TheNecklace(nodes); 83 | System.out.println("Case #" + (i + 1)); 84 | if (necklace.path.size() != 0) { 85 | necklace.path 86 | .forEach(x -> System.out.println(x[0] + " " + x[1])); 87 | } else { 88 | System.out.println("some beads may be lost"); 89 | } 90 | if (i < n - 1) { 91 | System.out.println(); 92 | } 93 | } 94 | } 95 | 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/Chapter10/TouristGuide.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class TouristGuide { 4 | private final Set cutVertices = new HashSet<>(); 5 | private final Set visited = new HashSet<>(); 6 | private final Map parent = new HashMap<>(); 7 | private final Map depths = new HashMap<>(); 8 | private final Map low = new HashMap<>(); 9 | private final Map> graph; 10 | 11 | public TouristGuide(Map> graph) { 12 | this.graph = graph; 13 | Set processed = new HashSet<>(); 14 | Set roots = new HashSet<>(graph.keySet()); 15 | while (processed.size() != graph.keySet().size()) { 16 | findCutVertices(roots.iterator().next(), 0); 17 | processed.addAll(visited); 18 | roots.removeAll(visited); 19 | } 20 | } 21 | 22 | public Set getCutVertices() { 23 | return cutVertices; 24 | } 25 | 26 | private void findCutVertices(String v, int d) { 27 | visited.add(v); 28 | depths.put(v, d); 29 | low.put(v, d); 30 | int childCount = 0; 31 | boolean isCutVertix = false; 32 | for (String n : graph.get(v)) { 33 | if (!visited.contains(n)) { 34 | parent.put(n, v); 35 | findCutVertices(n, d + 1); 36 | childCount++; 37 | if (low.get(n) >= depths.get(v)) { 38 | isCutVertix = true; 39 | } 40 | low.put(v, Math.min(low.get(v), low.get(n))); 41 | } else if (!n.equals(parent.get(v))) { 42 | low.put(v, Math.min(low.get(v), depths.get(n))); 43 | } 44 | } 45 | if ((parent.containsKey(v) && isCutVertix) || 46 | (!parent.containsKey(v) && childCount > 1)) { 47 | cutVertices.add(v); 48 | } 49 | } 50 | 51 | public static void main(String[] args) { 52 | Scanner s = new Scanner(System.in); 53 | int n = 0; 54 | int c = 0; 55 | while ((n = s.nextInt()) != 0) { 56 | c++; 57 | if (c > 1) { 58 | System.out.println(); 59 | } 60 | s.nextLine(); 61 | for (int i = 0; i < n; ++i) { 62 | s.nextLine(); 63 | } 64 | Map> graph = new HashMap<>(); 65 | int edgesCount = s.nextInt(); 66 | s.nextLine(); 67 | for (int i = 0; i < edgesCount; ++i) { 68 | String[] edge = s.nextLine().replaceAll("\\s+", " ").split(" "); 69 | assert (edge.length == 2); 70 | graph.putIfAbsent(edge[0], new HashSet<>()); 71 | graph.putIfAbsent(edge[1], new HashSet<>()); 72 | graph.get(edge[0]).add(edge[1]); 73 | graph.get(edge[1]).add(edge[0]); 74 | } 75 | TouristGuide t = new TouristGuide(graph); 76 | List cutPoints = new ArrayList<>(t.getCutVertices()); 77 | cutPoints.sort(String::compareTo); 78 | System.out.println(String.format("City map #%d: %d camera(s) found", c, cutPoints.size())); 79 | cutPoints.forEach(System.out::println); 80 | } 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/Chapter10/War.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class War { 4 | private final int[] friends; 5 | private final int n; 6 | 7 | public War(int n) { 8 | this.n = n; 9 | friends = new int[2 * (n + 1)]; 10 | for (int i = 0; i < 2 * (n + 1); ++i) { 11 | friends[i] = i; 12 | } 13 | } 14 | 15 | public int enemy(int i) { 16 | return i + n; 17 | } 18 | 19 | public int find(int i) { 20 | if (friends[i] != i) { 21 | friends[i] = find(friends[i]); 22 | } 23 | return friends[i]; 24 | } 25 | 26 | public void union(int i, int j) { 27 | if (find(i) != find(j)) { 28 | friends[find(j)] = find(i); 29 | } 30 | } 31 | 32 | private boolean setFriends(int i, int j) { 33 | if (areEnemies(i, j)) { 34 | return false; 35 | } 36 | union(i, j); 37 | union(enemy(i), enemy(j)); 38 | return true; 39 | } 40 | 41 | private boolean setEnemies(int i, int j) { 42 | if (areFriends(i, j)) { 43 | return false; 44 | } 45 | union(i, enemy(j)); 46 | union(j, enemy(i)); 47 | return true; 48 | } 49 | 50 | private boolean areFriends(int i, int j) { 51 | return find(i) == find(j) || 52 | find(enemy(i)) == find(enemy(j)); 53 | } 54 | 55 | private boolean areEnemies(int i, int j) { 56 | return find(i) == find(enemy(j)) || 57 | find(j) == find(enemy(i)); 58 | } 59 | 60 | public static void main(String[] args) { 61 | Scanner s = new Scanner(System.in); 62 | War war = new War(s.nextInt()); 63 | while (s.hasNextInt()) { 64 | switch (s.nextInt()) { 65 | case 0: 66 | return; 67 | case 1: 68 | if (!war.setFriends(s.nextInt(), s.nextInt())) { 69 | System.out.println(-1); 70 | } 71 | break; 72 | case 2: 73 | if (!war.setEnemies(s.nextInt(), s.nextInt())) { 74 | System.out.println(-1); 75 | } 76 | break; 77 | case 3: 78 | System.out.println(war.areFriends(s.nextInt(), s.nextInt()) ? 1 : 0); 79 | break; 80 | case 4: 81 | System.out.println(war.areEnemies(s.nextInt(), s.nextInt()) ? 1 : 0); 82 | break; 83 | default: 84 | throw new IllegalArgumentException(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/Chapter11/CuttingSticks.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | 3 | public class CuttingSticks { 4 | private final int[] cuts; 5 | private final int length; 6 | private final Integer[][] memo = new Integer[1000][1000]; 7 | 8 | public CuttingSticks(int[] cuts, int length) { 9 | this.cuts = cuts; 10 | this.length = length; 11 | } 12 | 13 | public int solve() { 14 | return solve(0, length); 15 | } 16 | 17 | private int solve(int start, int end) { 18 | if (memo[start][end] != null) { 19 | return memo[start][end]; 20 | } 21 | int min = Integer.MAX_VALUE; 22 | for (int i = 0; i < cuts.length; ++i) { 23 | if (cuts[i] > start && cuts[i] < end) { 24 | min = Math.min(min, solve(start, cuts[i]) + solve(cuts[i], end)); 25 | } 26 | } 27 | memo[start][end] = min < Integer.MAX_VALUE ? (end - start) + min : 0; 28 | return memo[start][end]; 29 | } 30 | 31 | public static void main(String[] args) { 32 | Scanner s = new Scanner(System.in); 33 | while (true) { 34 | int length = s.nextInt(); 35 | if (length == 0) { 36 | break; 37 | } 38 | int n = s.nextInt(); 39 | int[] cuts = new int[n]; 40 | for (int i = 0; i < n; ++i) { 41 | cuts[i] = s.nextInt(); 42 | } 43 | CuttingSticks solver = new CuttingSticks(cuts, length); 44 | System.out.println(String.format("The minimum cutting is %d.", solver.solve())); 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/Chapter11/DistinctSubsequences.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigInteger; 5 | 6 | public class Main { 7 | private BigInteger slowRecursive(String line, String subs) { 8 | BigInteger[][] memo = new BigInteger[line.length()+1][subs.length()+1]; 9 | return slowRecursive(line, subs, memo); 10 | } 11 | 12 | private BigInteger slowRecursive(String line, String subs, BigInteger[][] memo) { 13 | BigInteger count = BigInteger.ZERO; 14 | 15 | if (memo[line.length()][subs.length()] != null) { 16 | return memo[line.length()][subs.length()]; 17 | } 18 | 19 | for (int i = line.length() - 1; i >= 0; --i) { 20 | if (line.charAt(i) == subs.charAt(subs.length() - 1)) { 21 | if (subs.length() == 1) { 22 | count = count.add(BigInteger.ONE); 23 | } else { 24 | count = count.add(slowRecursive(line.substring(0, i), 25 | subs.substring(0, subs.length() - 1), memo)); 26 | } 27 | } 28 | } 29 | 30 | memo[line.length()][subs.length()] = count; 31 | return count; 32 | } 33 | 34 | private BigInteger fastTabular(String line, String subs) { 35 | BigInteger[][] memo = new BigInteger[line.length() + 1][subs.length() + 1]; 36 | for (int i = 0; i <= subs.length(); ++i) { 37 | memo[0][i] = BigInteger.ZERO; 38 | } 39 | for (int i = 0; i <= line.length(); ++i) { 40 | memo[i][0] = BigInteger.ZERO; 41 | } 42 | for (int i = 1; i <= subs.length(); ++i) { 43 | for (int j = 1; j <= line.length(); ++j) { 44 | if (line.charAt(j - 1) == subs.charAt(i - 1)) { 45 | if (i == 1) { 46 | memo[j][i] = memo[j - 1][i].add(BigInteger.ONE); 47 | } else { 48 | memo[j][i] = memo[j - 1][i].add(memo[j - 1][i - 1]); 49 | } 50 | } else { 51 | memo[j][i] = memo[j - 1][i]; 52 | } 53 | } 54 | } 55 | return memo[line.length()][subs.length()]; 56 | } 57 | 58 | public static void main(String[] args) throws IOException { 59 | BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 60 | int n = Integer.parseInt(reader.readLine().trim()); 61 | for (int i = 0; i < n; ++i) { 62 | String line = reader.readLine().trim(); 63 | String subs = reader.readLine().trim(); 64 | Main solver = new Main(); 65 | //System.out.println(solver.slowRecursive(line, subs)); 66 | System.out.println(solver.fastTabular(line, subs)); 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/Chapter11/FerryLoading.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class FerryLoading { 4 | private final List queue; 5 | private final int ferryLength; 6 | private final Map>>> memo = new HashMap<>(); 7 | 8 | public FerryLoading(int ferryLength, List queue) { 9 | this.ferryLength = ferryLength * 100; 10 | this.queue = queue; 11 | } 12 | 13 | private Deque solve() { 14 | return solve(0, new ArrayDeque<>(), 0, 0); 15 | } 16 | 17 | private Deque solve(int i, Deque solution, int leftLength, int rightLength) { 18 | if (i > queue.size() - 1) { 19 | return new ArrayDeque<>(solution); 20 | } 21 | Integer next = queue.get(i); 22 | int min = Math.min(leftLength, rightLength); 23 | int max = Math.max(leftLength, rightLength); 24 | 25 | if (memo.get(min) != null) { 26 | Map> m = memo.get(min).get(max); 27 | if (m != null && m.containsKey(i)) { 28 | return m.get(i); 29 | } 30 | } 31 | 32 | Deque leftSolution = null; 33 | if (next + leftLength <= ferryLength) { 34 | solution.addLast(true); 35 | leftSolution = solve(i + 1, solution, next + leftLength, rightLength); 36 | solution.removeLast(); 37 | } 38 | 39 | Deque rightSolution = null; 40 | if (next + rightLength <= ferryLength) { 41 | solution.addLast(false); 42 | rightSolution = solve(i + 1, solution, leftLength, next + rightLength); 43 | solution.removeLast(); 44 | } 45 | 46 | Deque finalSolution = null; 47 | if (leftSolution == null && rightSolution == null) { 48 | finalSolution = new ArrayDeque<>(solution); 49 | } else if (leftSolution == null || rightSolution == null) { 50 | finalSolution = leftSolution == null ? rightSolution : leftSolution; 51 | } else { 52 | finalSolution = leftSolution.size() > rightSolution.size() ? leftSolution : rightSolution; 53 | } 54 | 55 | memo.putIfAbsent(min, new HashMap<>()); 56 | memo.get(min).putIfAbsent(max, new HashMap<>()); 57 | memo.get(min).get(max).putIfAbsent(i, finalSolution); 58 | return finalSolution; 59 | } 60 | 61 | public static void main(String[] args) { 62 | Scanner s = new Scanner(System.in); 63 | int n = s.nextInt(); 64 | for (int i = 0; i < n; i++) { 65 | List queue = new ArrayList<>(); 66 | int ferry = s.nextInt(); 67 | int k; 68 | while ((k = s.nextInt()) != 0) { 69 | queue.add(k); 70 | } 71 | FerryLoading solver = new FerryLoading(ferry, queue); 72 | Deque solution = solver.solve(); 73 | System.out.println(solution.size()); 74 | solution.stream().map(x -> x ? "starboard" : "port").forEach(System.out::println); 75 | if (i < n - 1) { 76 | System.out.println(); 77 | } 78 | } 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /src/Chapter11/IsBiggerSmarter.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Scanner; 7 | 8 | public class IsBiggerSmarter { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | public static int[] solve(List input) { 13 | if (input.size() == 1) { 14 | return new int[] { 0 }; 15 | } 16 | List sorted = new ArrayList<>(input); 17 | Collections.sort(sorted, (x, y) -> Integer.compare(x[0], y[0])); 18 | int[] res = new int[sorted.size()]; 19 | int[] ref = new int[sorted.size()]; 20 | int index = 0; 21 | 22 | for (int i = 0; i < sorted.size(); ++i) { 23 | res[i] = 1; 24 | ref[0] = -1; 25 | for (int j = 0; j < i; ++j) { 26 | if (sorted.get(j)[0] < sorted.get(i)[0] && 27 | sorted.get(j)[1] > sorted.get(i)[1]) { 28 | if (res[i] < res[j] + 1) { 29 | res[i] = res[j] + 1; 30 | ref[i] = j; 31 | if (index == -1 || res[i] > res[index]) { 32 | index = i; 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | int[] solution = new int[res[index]]; 40 | int i = solution.length - 1; 41 | do { 42 | solution[i] = sorted.get(index)[2]; 43 | index = ref[index]; 44 | i--; 45 | } while (index != -1 && i >= 0); 46 | 47 | return solution; 48 | } 49 | 50 | public static void main(String[] args) throws Exception { 51 | String currentLine; 52 | List input = new ArrayList<>(); 53 | int i = 0; 54 | while ((currentLine = reader.readLine()) != null) { 55 | Scanner s = new Scanner(currentLine); 56 | input.add(new int[] { s.nextInt(), s.nextInt(), i }); 57 | s.close(); 58 | i++; 59 | } 60 | int[] solution = solve(input); 61 | System.out.println(solution.length); 62 | for (int idx : solution) { 63 | System.out.println(idx + 1); 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/Chapter11/UnidirectionalTSP.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.util.Scanner; 3 | 4 | import static java.util.Arrays.stream; 5 | import static java.util.stream.Collectors.joining; 6 | 7 | public class UnidirectionalTSP { 8 | private static class Cell { 9 | Cell next; 10 | int row; 11 | int value; 12 | int minPath; 13 | 14 | public Cell(int value, int row) { 15 | this.value = value; 16 | this.minPath = Integer.MAX_VALUE; 17 | this.row = row; 18 | } 19 | } 20 | 21 | final Cell[][] table; 22 | final int m; 23 | final int n; 24 | int minPath; 25 | int[] path; 26 | 27 | public UnidirectionalTSP(Cell[][] table, int m, int n) { 28 | this.table = table; 29 | this.m = m; 30 | this.n = n; 31 | this.path = new int[n]; 32 | this.minPath = Integer.MAX_VALUE; 33 | solve(); 34 | } 35 | 36 | private Cell get(int row, int col) { 37 | if (row > m - 1) { 38 | return table[0][col]; 39 | } else if (row < 0) { 40 | return table[m - 1][col]; 41 | } 42 | return table[row][col]; 43 | } 44 | 45 | private void solve() { 46 | for (int row = 0; row < m; ++row) { 47 | Cell cell = get(row, n - 1); 48 | cell.minPath = cell.value; 49 | cell.next = null; 50 | } 51 | for (int col = n - 2; col >= 0; --col) { 52 | for (int row = 0; row < m; ++row) { 53 | Cell cell = get(row, col); 54 | int min = Integer.MAX_VALUE; 55 | for (int i = -1; i <= 1; ++i) { 56 | Cell next = get(row + i, col + 1); 57 | if (min > next.minPath) { 58 | min = next.minPath; 59 | cell.next = next; 60 | } else if (min == next.minPath) { 61 | if (cell.next == null || (cell.next != null && cell.next.row > next.row)) { 62 | cell.next = next; 63 | } 64 | } 65 | } 66 | cell.minPath = min + cell.value; 67 | } 68 | } 69 | Cell cell = null; 70 | for (int row = 0; row < m; ++row) { 71 | Cell curr = get(row, 0); 72 | if (cell == null || (cell != null && curr.minPath < cell.minPath)) { 73 | cell = curr; 74 | } 75 | } 76 | 77 | this.minPath = cell.minPath; 78 | for (int col = 0; col < n; ++col) { 79 | path[col] = cell.row + 1; 80 | cell = cell.next; 81 | } 82 | } 83 | 84 | public static void main(String[] args) throws IOException { 85 | Scanner s = new Scanner(System.in); 86 | while (s.hasNextInt()) { 87 | int m = s.nextInt(); // rows 88 | int n = s.nextInt(); // cols 89 | Cell[][] table = new Cell[m][n]; 90 | for (int i = 0; i < m * n; ++i) { 91 | table[i / n][i % n] = new Cell(s.nextInt(), i / n); 92 | } 93 | UnidirectionalTSP main = new UnidirectionalTSP(table, m, n); 94 | System.out.println(stream(main.path).mapToObj(String::valueOf).collect(joining(" "))); 95 | System.out.println(main.minPath); 96 | } 97 | } 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/Chapter11/WeightsAndMeasures.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.Scanner; 8 | 9 | public class WeightsAndMeasures { 10 | private static class Turtle { 11 | int weight; 12 | int strength; 13 | 14 | public Turtle(int weight, int strength) { 15 | this.weight = weight; 16 | this.strength = strength; 17 | } 18 | } 19 | 20 | public static int solve(List input) { 21 | input.sort(Comparator.comparingInt(x -> x.strength)); 22 | int[][] W = new int[2][input.size() + 1]; 23 | W[0][0] = 0; 24 | for (int i = 1; i <= input.size(); ++i) { 25 | W[0][i] = Integer.MAX_VALUE; 26 | W[1][i] = Integer.MAX_VALUE; 27 | } 28 | 29 | for (int i = 1; i <= input.size(); ++i) { 30 | Turtle t = input.get(i - 1); 31 | for (int k = i; k >= 1; --k) { 32 | if (W[0][k - 1] <= (t.strength - t.weight)) { 33 | W[1][k] = Math.min(W[0][k], W[0][k - 1] + t.weight); 34 | } else { 35 | W[1][k] = W[0][k]; 36 | } 37 | } 38 | System.arraycopy(W[1], 0, W[0], 0, W[1].length); 39 | for (int k = 1; k <= input.size(); ++k) { 40 | W[1][k] = Integer.MAX_VALUE; 41 | } 42 | } 43 | for (int i = input.size(); i >= 0; --i) { 44 | if (W[0][i] < Integer.MAX_VALUE) { 45 | return i; 46 | } 47 | } 48 | return 1; 49 | } 50 | 51 | 52 | public static void main(String[] args) throws IOException { 53 | BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 54 | String line; 55 | List input = new ArrayList<>(); 56 | while ((line = reader.readLine()) != null) { 57 | Scanner scanner = new Scanner(line); 58 | input.add(new Turtle(scanner.nextInt(), scanner.nextInt())); 59 | } 60 | System.out.println(solve(input)); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/Chapter12/AntOnAChessboard.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | 3 | public class AntOnAChessboard { 4 | private static long[] get(long v) { 5 | long k = (long) Math.ceil(Math.sqrt(v)); 6 | long m = k * k - k + 1; 7 | boolean isOdd = k % 2 == 1; 8 | if (v == m) { 9 | return new long[]{k, k}; 10 | } else if (v >= m) { 11 | if (isOdd) { 12 | return new long[]{k * k - v + 1, k}; 13 | } 14 | return new long[]{k, k * k - v + 1}; 15 | } else { 16 | if (isOdd) { 17 | return new long[]{k, k - (m - v)}; 18 | } 19 | return new long[]{k - (m - v), k}; 20 | } 21 | } 22 | 23 | public static void main(String[] args) { 24 | Scanner s = new Scanner(System.in); 25 | while (true) { 26 | long v = s.nextLong(); 27 | if (v == 0) { 28 | break; 29 | } 30 | long[] ans = get(v); 31 | System.out.println(String.format("%d %d", ans[0], ans[1])); 32 | } 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/Chapter12/BeeMaja.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class BeeMaja { 6 | private static int[][] PATTERN = { 7 | {0, 1}, {-1, 1}, {-1, 0}, {0, -1}, {1, -1}, {1, 0}, {0, 1} 8 | }; 9 | 10 | private static int[][] getLookup() { 11 | int[][] lookup = new int[100000][2]; 12 | int x = 0; 13 | int y = 0; 14 | int l = 0; 15 | int c = 0; 16 | int i = 0; 17 | lookup[0] = new int[]{0, 0}; 18 | while (c < 100000) { 19 | int m = i % 7; 20 | if (m == 0) ++l; 21 | int r; 22 | if (m == 0) { 23 | r = 1; 24 | } else if (m == 1) { 25 | r = l - 1; 26 | } else { 27 | r = l; 28 | } 29 | for (int j = 0; j < r; j++) { 30 | x += PATTERN[m][0]; 31 | y += PATTERN[m][1]; 32 | c++; 33 | if (c == 100000) return lookup; 34 | lookup[c] = new int[]{x, y}; 35 | } 36 | i++; 37 | } 38 | return lookup; 39 | } 40 | 41 | private static final BufferedReader reader = new BufferedReader( 42 | new InputStreamReader(System.in)); 43 | 44 | public static void main(String[] args) throws IOException { 45 | int[][] lookup = getLookup(); 46 | String currentLine; 47 | while ((currentLine = reader.readLine()) != null && 48 | !currentLine.trim().isEmpty()) { 49 | int n = Integer.parseInt(currentLine) - 1; 50 | System.out.println(lookup[n][0] + " " + lookup[n][1]); 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/Chapter12/DermubaTriangle.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.RoundingMode; 5 | import java.text.DecimalFormat; 6 | import java.util.Scanner; 7 | 8 | public class DermubaTriangle { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | public static final double SQRT3 = Math.sqrt(3); 13 | private static double D2 = SQRT3 / 6.0; 14 | private static double D1 = SQRT3 / 2.0 - D2; 15 | 16 | private static double adjust(int sn, int n) { 17 | if (sn % 2 == 0) { 18 | return n % 2 == 0 ? D2 : D1; 19 | } else { 20 | return n % 2 == 0 ? D1 : D2; 21 | } 22 | } 23 | 24 | private static double calculate(int n, int m) { 25 | int sn = (int) Math.floor(Math.sqrt((double) n)); 26 | int sm = (int) Math.floor(Math.sqrt((double) m)); 27 | double d = (sm - sn) / 2.0; 28 | 29 | double l1 = -(n - sn * sn) / 2.0; 30 | double ll = l1 - d; 31 | double l2 = +(m - sm * sm) / 2.0; 32 | double x = l2 + ll; 33 | 34 | double y = (sm - sn) * SQRT3 / 2.0; 35 | y += adjust(sn, n); 36 | y -= adjust(sm, m); 37 | return Math.sqrt(y * y + x * x); 38 | } 39 | 40 | public static void main(String[] args) throws IOException { 41 | DecimalFormat df = new DecimalFormat("0.000"); 42 | df.setRoundingMode(RoundingMode.HALF_EVEN); 43 | String currentLine; 44 | while ((currentLine = reader.readLine()) != null && 45 | !currentLine.trim().isEmpty()) { 46 | Scanner s = new Scanner(currentLine); 47 | int n = s.nextInt(); 48 | int m = s.nextInt(); 49 | double distance = calculate(n, m); 50 | System.out.println(df.format(distance)); 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/Chapter12/Robbery.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | public class Robbery { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | private static final Boolean HIDDEN = Boolean.FALSE; 12 | private static final Boolean VISIBLE = Boolean.TRUE; 13 | private static int[][] DIRECTION = {{0, 0}, {-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 14 | 15 | private static boolean inCity(int x, int y, Boolean[][][] city) { 16 | return x >= 1 && x < city[0].length && y >= 1 && y < city.length; 17 | } 18 | 19 | private static Boolean visibility(Boolean[][][] city, int x, int y, int time) { 20 | if (!inCity(x, y, city)) { 21 | return VISIBLE; 22 | } 23 | if (city[y][x][time] != null) { 24 | return city[y][x][time]; 25 | } 26 | if (time == 1) { 27 | city[y][x][time] = HIDDEN; 28 | return city[y][x][time]; 29 | } 30 | 31 | boolean hidden = false; 32 | for (int i = 0; i < DIRECTION.length; i++) { 33 | boolean isHidden = visibility( 34 | city, 35 | x + DIRECTION[i][0], 36 | y + DIRECTION[i][1], 37 | time - 1) == HIDDEN; 38 | hidden |= isHidden; 39 | } 40 | 41 | city[y][x][time] = hidden ? HIDDEN : VISIBLE; 42 | return city[y][x][time]; 43 | } 44 | 45 | private static int[] findUniqueLocation(Boolean[][][] city, int time) { 46 | List locations = new ArrayList<>(); 47 | for (int y = 1; y < city.length; y++) { 48 | for (int x = 1; x < city[0].length; x++) { 49 | if (city[y][x][time] == HIDDEN) { 50 | locations.add(new int[]{x, y}); 51 | } 52 | } 53 | } 54 | return locations.size() == 1 ? locations.get(0) : null; 55 | } 56 | 57 | public static void main(String[] args) throws IOException { 58 | String currentLine; 59 | int count = 0; 60 | while ((currentLine = reader.readLine()) != null) { 61 | if (currentLine.isEmpty()) { 62 | continue; 63 | } 64 | Integer[] input = Arrays.stream( 65 | currentLine.trim().split(" ")).map(Integer::parseInt).toArray(l -> new Integer[l]); 66 | int w = input[0]; 67 | int h = input[1]; 68 | int t = input[2]; 69 | if (w == 0 && h == 0 && t == 0) break; 70 | System.out.println("Robbery #" + (++count) + ":"); 71 | Boolean[][][] city = new Boolean[h + 1][w + 1][t + 1]; // h x w x t 72 | int n = Integer.parseInt(reader.readLine()); 73 | for (int i = 0; i < n; i++) { 74 | Integer[] m = Arrays.stream( 75 | reader.readLine().trim().split(" ")) 76 | .map(Integer::parseInt).toArray(l -> new Integer[l]); 77 | // 0 time 1 left 2 top 3 right 4 bottom 78 | for (int x = m[1]; x <= m[3]; x++) { 79 | for (int y = m[2]; y <= m[4]; y++) { 80 | city[y][x][m[0]] = VISIBLE; 81 | } 82 | } 83 | } 84 | 85 | boolean escaped = true; 86 | for (int y = 1; y <= h; y++) { 87 | for (int x = 1; x <= w; x++) { 88 | if (visibility(city, x, y, t) == HIDDEN) { 89 | escaped = false; 90 | } 91 | } 92 | } 93 | 94 | if (escaped) { 95 | System.out.println("The robber has escaped."); 96 | } else { 97 | List output = new ArrayList<>(); 98 | for (int time = 1; time <= t; time++) { 99 | int[] loc = findUniqueLocation(city, time); 100 | if (loc != null) { 101 | output.add("Time step " + time + 102 | ": The robber has been at " + loc[0] + "," + loc[1] + "."); 103 | } 104 | } 105 | if (output.isEmpty()) { 106 | System.out.println("Nothing known."); 107 | } else { 108 | output.forEach(System.out::println); 109 | } 110 | } 111 | System.out.println(); 112 | } 113 | } 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/Chapter12/SqrRectsCubesBoxes.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class SqrRectsCubesBoxes { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | 9 | private static long[] calculate(int n) { 10 | long[] res = new long[]{0, 0, 0, 0, 0, 0}; 11 | for (int i = 1; i <= n; i++) { 12 | for (int j = i; j <= n; j++) { 13 | int ij = i * j; 14 | if (i <= n && j <= n) { 15 | if (i == j) { 16 | res[0] += ij; 17 | } else { 18 | res[1] += ij * 2; 19 | } 20 | } 21 | for (int k = j; k <= n; k++) { 22 | int ijk = ij * k; 23 | if (i <= n && j <= n && k <= n) { 24 | boolean a = i == j; 25 | boolean b = j == k; 26 | if (a && b) { 27 | res[2] += ijk; 28 | } else if (a && !b || !a && b ) { 29 | res[3] += ijk * 3; 30 | } else { 31 | res[3] += ijk * 6; 32 | } 33 | } 34 | for (int l = k; l <= n; l++) { 35 | boolean a = i == j; 36 | boolean b = j == k; 37 | boolean c = k == l; 38 | if (i == j && j == k && k == l) { 39 | res[4] += ijk * l; 40 | } else { 41 | long f = 0; 42 | if (a && !b && !c || !a && b && !c || !a && !b && c) { 43 | f = 12; 44 | } else if (a && b && !c || !a && b && c) { 45 | f = 4; 46 | } else if (!a && !b && !c) { 47 | f = 24; 48 | } else { 49 | f = 6; 50 | } 51 | res[5] += ijk * l * f; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | return res; 58 | } 59 | 60 | public static void main(String[] args) throws IOException { 61 | long[][] lookup = new long[101][6]; 62 | for (int i = 0; i <= 100; i++) { 63 | lookup[i] = calculate(i); 64 | } 65 | String currentLine; 66 | while ((currentLine = reader.readLine()) != null && 67 | !currentLine.trim().isEmpty()) { 68 | int n = Integer.parseInt(currentLine); 69 | long[] res = lookup[n]; 70 | System.out.println(String.format( 71 | "%d %d %d %d %d %d", res[0], res[1], res[2], res[3], res[4], res[5])); 72 | } 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/Chapter13/BirthdayCake.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class BirthdayCake { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | private static int X = 0; 9 | private static int Y = 1; 10 | 11 | private static boolean isSplit(int[][] cherry, int x, int y) { 12 | int A = y; 13 | int B = -x; 14 | int left = 0; 15 | int right = 0; 16 | 17 | for (int i = 0; i < cherry.length; i++) { 18 | int[] a = cherry[i]; 19 | int r = A * a[X] + B * a[Y]; 20 | if (r == 0) { 21 | return false; 22 | } else if (r < 0) { 23 | left++; 24 | } else { 25 | right++; 26 | } 27 | } 28 | 29 | return left == right; 30 | } 31 | 32 | private static int[] solve(int[][] cherry) { 33 | for (int i = 0; i < cherry.length; i++) { 34 | for (int j = i + 1; j < cherry.length; j++) { 35 | int[] a = cherry[i]; 36 | int[] b = cherry[j]; 37 | 38 | double mx = (b[X] + a[X]) / 2.0; 39 | double my = (b[Y] + a[Y]) / 2.0; 40 | 41 | if (mx > 0) { 42 | double k = my / mx; 43 | for (int l = 1; l <= 500; l++) { 44 | int x = l; 45 | int y = (int) Math.round(x * k); 46 | if (isSplit(cherry, x, y)) { 47 | return new int[]{y, -x}; 48 | } 49 | } 50 | } else if (mx < 0) { 51 | double k = my / mx; 52 | for (int l = -1; l >= -500; l--) { 53 | int x = l; 54 | int y = (int) Math.round(x * k); 55 | if (isSplit(cherry, x, y)) { 56 | return new int[]{y, -x}; 57 | } 58 | } 59 | } else { 60 | if (isSplit((cherry), 0, 1)) { 61 | return new int[]{1, 0}; 62 | } 63 | } 64 | } 65 | } 66 | return new int[]{0, 0}; 67 | } 68 | 69 | public static void main(String[] args) throws IOException { 70 | int n = Integer.parseInt(reader.readLine()); 71 | while (n != 0) { 72 | int[][] cherry = new int[2 * n][2]; 73 | for (int i = 0; i < 2 * n; i++) { 74 | String[] c = reader.readLine().split(" "); 75 | int x = Integer.parseInt(c[0]); 76 | int y = Integer.parseInt(c[1]); 77 | cherry[i] = new int[]{x, y}; 78 | } 79 | int[] solution = solve(cherry); 80 | System.out.println(solution[0] + " " + solution[1]); 81 | n = Integer.parseInt(reader.readLine()); 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/Chapter13/ChocolateChipCookies.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class ChocolateChipCookies { 8 | private static final BufferedReader reader = new BufferedReader( 9 | new InputStreamReader(System.in)); 10 | private static final double EPS = 0.00000001; 11 | private static double R = 2.5; 12 | private static int X = 0; 13 | private static int Y = 1; 14 | 15 | private static double[][] centers(double[] a, double b[], double h) { 16 | double[] m = {a[X] + (b[X] - a[X]) / 2.0, a[Y] + (b[Y] - a[Y]) / 2.0}; 17 | 18 | double[] u1 = {-(b[Y] - a[Y]), b[X] - a[X]}; 19 | double[] u2 = {b[Y] - a[Y], -(b[X] - a[X])}; 20 | 21 | double n1 = Math.sqrt(u1[X] * u1[X] + u1[Y] * u1[Y]); 22 | double n2 = Math.sqrt(u2[X] * u2[X] + u2[Y] * u2[Y]); 23 | 24 | double[][] centers = { 25 | {m[X] + h * (u1[X] / n1), m[Y] + h * (u1[Y] / n1)}, 26 | {m[X] + h * (u2[X] / n2), m[Y] + h * (u2[Y] / n2)}, 27 | }; 28 | 29 | return centers; 30 | } 31 | 32 | private static int[] counts(double[][] c, List points) { 33 | int[] count = new int[]{0, 0}; 34 | for (int i = 0; i < points.size(); i++) { 35 | double[] p = points.get(i); 36 | for (int j = 0; j < 2; j++) { 37 | double len = Math.sqrt((c[j][X] - p[X]) * (c[j][X] - p[X]) + 38 | (c[j][Y] - p[Y]) * (c[j][Y] - p[Y])); 39 | if (len <= R || Math.abs(len - R) < EPS) count[j] += 1; 40 | } 41 | } 42 | return count; 43 | } 44 | 45 | public static void main(String[] args) throws IOException { 46 | int n = Integer.parseInt(reader.readLine()); 47 | reader.readLine(); 48 | 49 | String line; 50 | for (int i = 0; i < n; i++) { 51 | int max = 0; 52 | 53 | List points = new ArrayList<>(); 54 | while ((line = reader.readLine()) != null) { 55 | if (line.trim().equals("")) break; 56 | String[] l = line.trim().split(" "); 57 | double x = Double.parseDouble(l[0]); 58 | double y = Double.parseDouble(l[1]); 59 | points.add(new double[]{x, y}); 60 | } 61 | 62 | for (int j = 0; j < points.size(); j++) { 63 | for (int k = j; k < points.size(); k++) { 64 | if (i == k) continue; 65 | 66 | double[] p1 = points.get(j); 67 | double[] p2 = points.get(k); 68 | 69 | double len = Math.sqrt((p1[X] - p2[X]) * (p1[X] - p2[X]) + 70 | (p1[Y] - p2[Y]) * (p1[Y] - p2[Y])); 71 | if (len <= 2 * R || (Math.abs(len - 2 * R) < EPS)) { 72 | double h = Math.sqrt(R * R - (len / 2) * (len / 2)); 73 | double[][] centers = centers(p1, p2, h); 74 | int[] counts = counts(centers, points); 75 | max = Math.max(counts[0], max); 76 | max = Math.max(counts[1], max); 77 | } 78 | } 79 | } 80 | 81 | if (max > 0) { 82 | System.out.println(max); 83 | } else { 84 | System.out.println(1); 85 | } 86 | if (i != n - 1) { 87 | System.out.println(); 88 | } 89 | } 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /src/Chapter13/DogAndGopher.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.RoundingMode; 5 | import java.text.DecimalFormat; 6 | 7 | public class DogAndGopher { 8 | private static final BufferedReader reader = new BufferedReader( 9 | new InputStreamReader(System.in)); 10 | 11 | private static long len(double x, double y, double gx, double gy) { 12 | double lx = (gx - x) * (gx - x); 13 | double ly = (gy - y) * (gy - y); 14 | return Math.round(Math.sqrt(lx + ly) * 1000.0); 15 | } 16 | 17 | public static void main(String[] args) throws IOException { 18 | DecimalFormat df = new DecimalFormat("0.000"); 19 | df.setRoundingMode(RoundingMode.HALF_EVEN); 20 | 21 | String currentLine; 22 | while ((currentLine = reader.readLine()) != null) { 23 | if (currentLine.trim().isEmpty()) continue; 24 | String[] l = currentLine.split(" "); 25 | int n = Integer.parseInt(l[0]); 26 | double gx = Double.parseDouble(l[1]); 27 | double gy = Double.parseDouble(l[2]); 28 | double dx = Double.parseDouble(l[3]); 29 | double dy = Double.parseDouble(l[4]); 30 | boolean found = false; 31 | for (int i = 0; i < n; i++) { 32 | String[] hole = reader.readLine().split(" "); 33 | double x = Double.parseDouble(hole[0]); 34 | double y = Double.parseDouble(hole[1]); 35 | long len1 = len(x, y, gx, gy); 36 | long len2 = len(x, y, dx, dy); 37 | if ((len1 == 0 || len1*2 <= len2) && !found) { 38 | System.out.println("The gopher can escape through the hole at (" 39 | + df.format(x) + "," + df.format(y) + ")."); 40 | found = true; 41 | } 42 | } 43 | if (!found) { 44 | System.out.println("The gopher cannot escape."); 45 | } 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/Chapter13/RopeCrisisInRopeland.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.text.DecimalFormat; 4 | 5 | import static java.lang.Math.abs; 6 | import static java.lang.Math.acos; 7 | import static java.lang.Math.sqrt; 8 | 9 | public class RopeCrisisInRopeland { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | public static final double TWOPI = 2.0 * Math.PI; 13 | 14 | public static boolean crosses(double r, double ax, double ay, double bx, double by) { 15 | double dx = bx - ax; 16 | double dy = by - ay; 17 | double t = -(ax * dx + ay * dy) / (dx * dx + dy * dy); 18 | double projectionX = ax + t * dx; 19 | double projectionY = ay + t * dy; 20 | boolean projectionOnSegment = (t >= 0 && t <= 1); 21 | double distSqToProjection = projectionX * projectionX + projectionY * projectionY; 22 | return projectionOnSegment && distSqToProjection < r * r; 23 | } 24 | 25 | public static void main(String[] args) throws Exception { 26 | DecimalFormat df = new DecimalFormat("0.000"); 27 | int n = Integer.parseInt(reader.readLine()); 28 | for (int i = 0; i < n; i++) { 29 | String[] l = reader.readLine().trim().split(" "); 30 | 31 | double x1 = Double.parseDouble(l[0]); 32 | double y1 = Double.parseDouble(l[1]); 33 | double x2 = Double.parseDouble(l[2]); 34 | double y2 = Double.parseDouble(l[3]); 35 | double r = Double.parseDouble(l[4]); 36 | double angleAlpha = acos( 37 | (x1 * x2 + y1 * y2) / (sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2))); 38 | 39 | double lx2 = (x1) * (x1); 40 | double ly2 = (y1) * (y1); 41 | double len1 = sqrt(lx2 + ly2); 42 | double seg1 = sqrt(len1 * len1 - r * r); 43 | double asin1 = Math.asin(seg1 / len1); 44 | 45 | double lx1 = (x2) * (x2); 46 | double ly1 = (y2) * (y2); 47 | double len2 = sqrt(lx1 + ly1); 48 | double seg2 = sqrt(len2 * len2 - r * r); 49 | double asin2 = Math.asin(seg2 / len2); 50 | 51 | double angle = angleAlpha - asin1 - asin2; 52 | double arcLen = abs(angle / (TWOPI) * (TWOPI * r)); 53 | 54 | double lx = (x2 - x1) * (x2 - x1); 55 | double ly = (y2 - y1) * (y2 - y1); 56 | double seg1Seg2len = sqrt(lx + ly); 57 | 58 | if (crosses(r, x1, y1, x2, y2)) { 59 | System.out.println(df.format(arcLen + seg1 + seg2)); 60 | } else { 61 | System.out.println(df.format(seg1Seg2len)); 62 | } 63 | } 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/Chapter13/TheKnightsOfTheRoundTable.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.text.DecimalFormat; 5 | 6 | public class TheKnightsOfTheRoundTable { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | public static void main(String[] args) throws IOException { 11 | DecimalFormat df = new DecimalFormat("0.000"); 12 | String line; 13 | while ((line = reader.readLine()) != null) { 14 | String[] sides = line.trim().split(" "); 15 | double a = Double.parseDouble(sides[0]); 16 | double b = Double.parseDouble(sides[1]); 17 | double c = Double.parseDouble(sides[2]); 18 | double s = (a + b + c) / 2.0; 19 | double area = Math.sqrt(s * (s - a) * (s - b) * (s - c)); 20 | double r = 0.0; 21 | if (Math.abs(area) > 0.00000001) { 22 | r = area / s; 23 | } 24 | System.out.println("The radius of the round table is: " + df.format(r)); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/Chapter13/TheLargestSmallestBox.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.RoundingMode; 5 | import java.text.DecimalFormat; 6 | 7 | public class TheLargestSmallestBox { 8 | private static final BufferedReader reader = new BufferedReader( 9 | new InputStreamReader(System.in)); 10 | 11 | public static void main(String[] args) throws IOException { 12 | String line; 13 | DecimalFormat up = new DecimalFormat("0.000"); 14 | up.setRoundingMode(RoundingMode.UP); 15 | DecimalFormat halfDown = new DecimalFormat("0.000"); 16 | halfDown.setRoundingMode(RoundingMode.HALF_DOWN); 17 | while ((line = reader.readLine()) != null) { 18 | String[] s = line.trim().split(" "); 19 | double l = Double.parseDouble(s[0]); 20 | double w = Double.parseDouble(s[1]); 21 | double m = Math.min(l / 2.0, w / 2.0); 22 | 23 | double s1 = 1 / 6.0 * (-Math.sqrt(l * l - l * w + w * w) + l + w); 24 | double s2 = 1 / 6.0 * (Math.sqrt(l * l - l * w + w * w) + l + w); 25 | 26 | System.out.println(halfDown.format(s1) + " " 27 | + up.format(0) + " " + up.format(Math.min(m, s2))); 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/Chapter2/ContestScoreboard.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | public class ContestScoreboard { 14 | private static final BufferedReader reader = new BufferedReader( 15 | new InputStreamReader(System.in)); 16 | 17 | private static class Team implements Comparable { 18 | private final int num; 19 | private int totalTime; 20 | private Set solved = new HashSet<>(); 21 | private final int[] penalties = new int[10]; 22 | 23 | @Override 24 | public String toString() { 25 | return num + " " + solved.size() + " " + getTotalTime(); 26 | } 27 | 28 | public Team(int num) { 29 | this.num = num; 30 | } 31 | 32 | public int getTotalTime() { 33 | int time = totalTime; 34 | for (Integer problemId : solved) { 35 | time += penalties[problemId]; 36 | } 37 | return time; 38 | } 39 | 40 | public void update(Integer problem, Integer time, String verdict) { 41 | switch (verdict) { 42 | case "C": 43 | if (solved.add(problem)) { 44 | totalTime += time; 45 | } 46 | break; 47 | case "I": 48 | if (!solved.contains(problem)) { 49 | penalties[problem] += 20; 50 | } 51 | break; 52 | default: 53 | break; 54 | } 55 | } 56 | 57 | @Override 58 | public int compareTo(Team o) { 59 | int solvedCmp = Integer.compare(o.solved.size(), 60 | this.solved.size()); 61 | if (solvedCmp == 0) { 62 | int timeCmp = Integer.compare(getTotalTime(), o.getTotalTime()); 63 | if (timeCmp == 0) { 64 | return Integer.compare(this.num, o.num); 65 | } 66 | return timeCmp; 67 | } 68 | return solvedCmp; 69 | } 70 | } 71 | 72 | public static void main(String[] args) throws IOException { 73 | int cases = Integer.parseInt(reader.readLine().trim()); 74 | reader.readLine(); 75 | String currentLine = null; 76 | for (int i = 0; i < cases; ++i) { 77 | Map participants = new HashMap<>(); 78 | while ((currentLine = reader.readLine()) != null && 79 | !currentLine.trim().equals("")) { 80 | List inputLine = stream(currentLine.trim().split(" ")) 81 | .filter(x -> !x.equals("")) 82 | .collect(toList()); 83 | Integer num = Integer.parseInt(inputLine.get(0)); 84 | Integer problem = Integer.parseInt(inputLine.get(1)); 85 | Integer time = Integer.parseInt(inputLine.get(2)); 86 | String verdict = inputLine.get(3); 87 | if (!participants.containsKey(num)) { 88 | participants.put(num, new Team(num)); 89 | } 90 | participants.get(num).update(problem, time, verdict); 91 | } 92 | participants.values().stream().sorted() 93 | .forEach(System.out::println); 94 | if (i < cases - 1) { 95 | System.out.println(); 96 | } 97 | } 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/Chapter2/ErdosNumbers.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayDeque; 8 | import java.util.ArrayList; 9 | import java.util.Deque; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | public class ErdosNumbers { 19 | private static final BufferedReader reader = new BufferedReader( 20 | new InputStreamReader(System.in)); 21 | private static final Pattern namePattern = Pattern 22 | .compile("[\\w^.,]+\\s*,\\s*(\\w\\.)+\\s*[,:]"); 23 | 24 | private static final String ERDOS = "Erdos, P."; 25 | 26 | private static void add(Map> graph, 27 | List names) { 28 | for (int i = 0; i < names.size(); ++i) { 29 | String currName = names.get(i); 30 | if (!graph.containsKey(names.get(i))) { 31 | graph.put(currName, new HashSet()); 32 | } 33 | names.forEach(name -> { 34 | if (!currName.equalsIgnoreCase(name)) { 35 | graph.get(currName).add(name); 36 | } 37 | }); 38 | } 39 | } 40 | 41 | private static List getNames(String input) { 42 | List names = new ArrayList<>(); 43 | Matcher m = namePattern.matcher(input); 44 | while (m.find()) { 45 | names.add(input.substring(m.start(), m.end() - 1).trim()); 46 | } 47 | return names; 48 | } 49 | 50 | private static Map getAnswer( 51 | Map> graph) { 52 | Deque q = new ArrayDeque<>(); 53 | Set s = new HashSet(); 54 | Map r = new HashMap<>(); 55 | q.push(ERDOS); 56 | r.put(ERDOS, Integer.valueOf(0)); 57 | 58 | while (!q.isEmpty()) { 59 | String n = q.pop(); 60 | int depth = r.get(n); 61 | for (String x : graph.get(n)) { 62 | if (!s.contains(x)) { 63 | s.add(x); 64 | q.addLast(x); 65 | r.put(x, Integer.valueOf(depth + 1)); 66 | } 67 | } 68 | } 69 | 70 | return r; 71 | } 72 | 73 | public static void main(String[] args) throws IOException { 74 | int n = Integer.parseInt(reader.readLine().trim()); 75 | for (int i = 0; i < n; ++i) { 76 | List nm = stream(reader.readLine().trim().split(" ")) 77 | .filter(x -> !x.equals("")).map(Integer::parseInt) 78 | .collect(toList()); 79 | Map> graph = new HashMap<>(); 80 | for (int j = 0; j < nm.get(0); ++j) { 81 | add(graph, getNames(reader.readLine().trim())); 82 | } 83 | Map r = getAnswer(graph); 84 | System.out.println("Scenario " + (i + 1)); 85 | for (int j = 0; j < nm.get(1); ++j) { 86 | String name = reader.readLine().trim(); 87 | System.out.println(name + " " + 88 | (r.containsKey(name) ? r.get(name) : "infinity")); 89 | } 90 | } 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/Chapter2/Hartals.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.BitSet; 5 | 6 | public class Hartals { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | private static void set(int n, BitSet res, int s, int l, boolean v) { 11 | while (s <= n) { 12 | res.set(s, v); 13 | s += l; 14 | } 15 | } 16 | 17 | private static int solve(int n, int[] h) { 18 | BitSet res = new BitSet(n + 1); 19 | for (int i = 0; i < h.length; ++i) { 20 | set(n, res, h[i], h[i], true); 21 | } 22 | set(n, res, 6, 7, false); 23 | set(n, res, 7, 7, false); 24 | int count = 0; 25 | for (int i = 0; i < res.size(); ++i) { 26 | count += res.get(i) ? 1 : 0; 27 | } 28 | return count; 29 | } 30 | 31 | public static void main(String[] args) throws IOException { 32 | int cases = Integer.parseInt(reader.readLine().trim()); 33 | for (int i = 0; i < cases; ++i) { 34 | int n = Integer.parseInt(reader.readLine().trim()); 35 | int p = Integer.parseInt(reader.readLine().trim()); 36 | int[] h = new int[p]; 37 | for (int j = 0; j < p; ++j) { 38 | h[j] = Integer.parseInt(reader.readLine().trim()); 39 | } 40 | System.out.println(solve(n, h)); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/Chapter2/JollyJumpers.java: -------------------------------------------------------------------------------- 1 | import static java.lang.Math.abs; 2 | import static java.util.Arrays.stream; 3 | import static java.util.stream.Collectors.toList; 4 | import static java.util.stream.IntStream.range; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.List; 10 | 11 | class JollyJumpers { 12 | private static final BufferedReader reader = 13 | new BufferedReader(new InputStreamReader(System.in)); 14 | 15 | public static void main(String[] args) throws IOException { 16 | String currentLine; 17 | while ((currentLine = reader.readLine()) != null) { 18 | List nums = stream(currentLine.trim().split(" ")).filter(x -> !x.equals("")) 19 | .skip(1).map(Integer::parseInt).collect(toList()); 20 | int[] diffs = range(0, nums.size() - 1) 21 | .map(i -> abs(nums.get(i) - nums.get(i + 1))).distinct().sorted().toArray(); 22 | boolean isJolly = range(0, diffs.length).boxed() 23 | .map(i -> diffs[i] == i + 1).reduce(true, (x, y) -> x && y); 24 | System.out.println(diffs.length == nums.size() - 1 && isJolly ? "Jolly" : "Not jolly"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Chapter2/StackEmUp.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | import static java.util.Arrays.stream; 4 | import static java.util.stream.Collectors.toList; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.stream.Stream; 14 | 15 | public class StackEmUp { 16 | private static final int DECK_SIZE = 52; 17 | 18 | private static final BufferedReader reader = new BufferedReader( 19 | new InputStreamReader(System.in)); 20 | 21 | private static final Map map = initialize(); 22 | 23 | private static Map initialize() { 24 | Map map = new HashMap<>(); 25 | int k = 0; 26 | for (String suit : Stream.of("Clubs", "Diamonds", "Hearts", "Spades") 27 | .collect(toList())) { 28 | for (int i = 2; i <= 10; ++i) { 29 | map.put(Integer.valueOf(k++), i + " of " + suit); 30 | } 31 | map.put(Integer.valueOf(k++), "Jack of " + suit); 32 | map.put(Integer.valueOf(k++), "Queen of " + suit); 33 | map.put(Integer.valueOf(k++), "King of " + suit); 34 | map.put(Integer.valueOf(k++), "Ace of " + suit); 35 | } 36 | return map; 37 | } 38 | 39 | private static List newDeck() { 40 | return Stream.iterate(0, i -> i + 1).limit(DECK_SIZE) 41 | .collect(toList()); 42 | } 43 | 44 | private static List apply(List deck, 45 | List shuffle) { 46 | List output = newDeck(); 47 | for (int j = 0; j < shuffle.size(); ++j) { 48 | output.set(j, deck.get(shuffle.get(j))); 49 | } 50 | return output; 51 | } 52 | 53 | private static List shuffle(List shuffleIndexes, 54 | List> shuffles) { 55 | List deck = newDeck(); 56 | for (Integer i : shuffleIndexes) { 57 | deck = apply(deck, shuffles.get(i)); 58 | } 59 | return deck; 60 | } 61 | 62 | public static void main(String[] args) throws IOException { 63 | int cases = Integer.parseInt(reader.readLine().trim()); 64 | reader.readLine(); 65 | for (int i = 0; i < cases; ++i) { 66 | int n = Integer.parseInt(reader.readLine().trim()); 67 | List shuffles = new ArrayList<>(); 68 | String currentLine; 69 | while (shuffles.size() < n * DECK_SIZE) { 70 | currentLine = reader.readLine().trim(); 71 | shuffles.addAll(stream(currentLine.split(" ")) 72 | .filter(x -> !x.equals("")) 73 | .map(Integer::parseInt) 74 | .map(x -> x - 1) 75 | .collect(toList())); 76 | } 77 | List> shuffleList = new ArrayList>(); 78 | for (int j = 0; j < n; ++j) { 79 | shuffleList.add(shuffles.subList(j * DECK_SIZE, 80 | j * DECK_SIZE + DECK_SIZE)); 81 | } 82 | List shuffleIndexes = new ArrayList<>(); 83 | while ((currentLine = reader.readLine()) != null && 84 | !currentLine.trim().equalsIgnoreCase("")) { 85 | shuffleIndexes.add(Integer.parseInt(currentLine.trim()) - 1); 86 | } 87 | shuffle(shuffleIndexes, shuffleList) 88 | .forEach(x -> System.out.println(map.get(x))); 89 | if (i < cases - 1) { 90 | System.out.println(); 91 | } 92 | } 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/Chapter3/AutomatedJudgeScript.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Arrays; 5 | 6 | public class AutomatedJudgeScript { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | private static String read(int n) throws IOException { 11 | StringBuilder input = new StringBuilder(); 12 | int newlines = 0; 13 | while (newlines < n) { 14 | int c = reader.read(); 15 | if (c == '\n') { 16 | newlines++; 17 | } 18 | input.append((char) c); 19 | } 20 | return input.toString(); 21 | } 22 | 23 | public static void main(String[] args) throws IOException { 24 | int i = 0; 25 | while (true) { 26 | int n = Integer.parseInt(reader.readLine().trim()); 27 | if (n == 0) { 28 | break; 29 | } 30 | String src = read(n); 31 | String dst = read(Integer.parseInt(reader.readLine().trim())); 32 | 33 | System.out.print("Run #" + (++i) + ": "); 34 | if (src.equals(dst)) { 35 | System.out.println("Accepted"); 36 | } else { 37 | if (Arrays.equals( 38 | src.chars().filter(Character::isDigit).toArray(), 39 | dst.chars().filter(Character::isDigit).toArray())) { 40 | System.out.println("Presentation Error"); 41 | } else { 42 | System.out.println("Wrong Answer"); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/Chapter3/CommonPermutation.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | public class CommonPermutation { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | public static int[] runs(int[] arr) { 14 | int[] runs = new int[256]; 15 | for (int i = 0; i < arr.length; ++i) { 16 | runs[arr[i]] += 1; 17 | } 18 | return runs; 19 | } 20 | 21 | public static void main(String[] args) throws IOException { 22 | String currentLine; 23 | while ((currentLine = reader.readLine()) != null) { 24 | int[] line1 = currentLine.trim().chars().sorted().toArray(); 25 | int[] line2 = reader.readLine().chars().sorted().toArray(); 26 | int[] run1 = runs(line1); 27 | int[] run2 = runs(line2); 28 | List distinct = stream(line1).distinct().boxed() 29 | .collect(toList()); 30 | distinct.retainAll(stream(line2).distinct().boxed() 31 | .collect(toList())); 32 | 33 | StringBuilder longest = new StringBuilder(); 34 | for (int i = 0; i < distinct.size(); ++i) { 35 | int len = Math.min(run1[distinct.get(i)], 36 | run2[distinct.get(i)]); 37 | for (int j = 0; j < len; ++j) { 38 | longest.append((char) distinct.get(i).intValue()); 39 | } 40 | } 41 | System.out.println(longest); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Chapter3/CryptKickerII.java: -------------------------------------------------------------------------------- 1 | import static java.lang.Math.abs; 2 | import static java.util.stream.Collectors.toList; 3 | import static java.util.stream.IntStream.range; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | class CryptKickerII { 13 | private static final BufferedReader reader = 14 | new BufferedReader(new InputStreamReader(System.in)); 15 | private final int[] mapping = new int[128]; 16 | private static final String pangram = "the quick brown fox jumps over the lazy dog"; 17 | private static final String pangramSpaces = pangram.replaceAll("[^ ]", "."); 18 | private static final List pangramPattern = getPattern(pangram); 19 | 20 | private static List getPattern(String word) { 21 | return range(0, word.length()).map(i -> word.indexOf(word.charAt(i))) 22 | .boxed().collect(toList()); 23 | } 24 | 25 | private static boolean compare(List a, List b) { 26 | return a.size() == b.size() && range(0, a.size()) 27 | .map(i -> abs(a.get(i) - b.get(i))).sum() == 0; 28 | } 29 | 30 | private boolean isPangram(String input) { 31 | String line = String.join(" ", Arrays.stream(input.trim() 32 | .split(" ")).filter(x -> !x.equals("")).collect(toList())); 33 | return compare(pangramPattern, getPattern(line.toString())) && 34 | line.replaceAll("[^ ]", ".").equalsIgnoreCase(pangramSpaces); 35 | } 36 | 37 | public List decrypt(List input) { 38 | Arrays.fill(mapping, 0); 39 | List output = new ArrayList(); 40 | String encryptedPangram = input.stream() 41 | .filter(x -> isPangram(x)).findFirst().orElse(""); 42 | if (encryptedPangram.equalsIgnoreCase("")) { 43 | output.add("No solution."); 44 | return output; 45 | } 46 | 47 | for (int i = 0; i < encryptedPangram.length(); ++i) { 48 | mapping[encryptedPangram.charAt(i)] = pangram.charAt(i); 49 | } 50 | 51 | return input.stream().map(x -> { 52 | StringBuilder result = new StringBuilder(); 53 | x.chars().map(c -> c != ' ' ? mapping[c] : c) 54 | .forEachOrdered(c -> result.append((char) c)); 55 | return result.toString(); 56 | }).collect(toList()); 57 | } 58 | 59 | public static void main(String[] args) throws IOException { 60 | String currentLine; 61 | final int n = Integer.parseInt(reader.readLine().trim()); 62 | reader.readLine(); 63 | CryptKickerII cryptKicker = new CryptKickerII(); 64 | for (int i = 0; i < n; ++i) { 65 | List input = new ArrayList(); 66 | while ((currentLine = reader.readLine()) != null && 67 | !currentLine.trim().equalsIgnoreCase("")) { 68 | input.add(currentLine); 69 | } 70 | cryptKicker.decrypt(input).forEach(System.out::println); 71 | if (i < n - 1) { 72 | System.out.println(); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Chapter3/Doublets.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | import static java.util.Arrays.stream; 4 | import static java.util.stream.Collectors.toList; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.ArrayDeque; 10 | import java.util.ArrayList; 11 | import java.util.Comparator; 12 | import java.util.Deque; 13 | import java.util.HashMap; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.Set; 18 | import java.util.stream.Collectors; 19 | 20 | public class Doublets { 21 | private static final BufferedReader reader = new BufferedReader( 22 | new InputStreamReader(System.in)); 23 | 24 | private static List find(Map> graph, 25 | String from, 26 | String to) { 27 | 28 | if (from.equalsIgnoreCase(to)) { 29 | List output = new ArrayList<>(); 30 | output.add(from); 31 | output.add(to); 32 | return output; 33 | } 34 | 35 | Deque q = new ArrayDeque<>(); 36 | Set s = new HashSet(); 37 | Map r = new HashMap<>(); 38 | q.push(from); 39 | r.put(from, from); 40 | 41 | while (!q.isEmpty()) { 42 | String currWord = q.pop(); 43 | for (String adjacentWord : graph.get(currWord)) { 44 | if (!s.contains(adjacentWord)) { 45 | s.add(adjacentWord); 46 | q.addLast(adjacentWord); 47 | if (!r.containsKey(adjacentWord)) { 48 | r.put(adjacentWord, currWord); 49 | } 50 | } 51 | } 52 | if (r.containsKey(to)) { 53 | List output = new ArrayList<>(); 54 | String curr = to; 55 | while (!curr.equalsIgnoreCase(from)) { 56 | output.add(0, curr); 57 | curr = r.get(curr); 58 | } 59 | output.add(0, from); 60 | return output; 61 | } 62 | } 63 | 64 | return null; 65 | } 66 | 67 | private static boolean adjacent(String a, String b) { 68 | if (a.length() != b.length()) { 69 | return false; 70 | } 71 | int diffCount = 0; 72 | for (int i = 0; i < a.length(); ++i) { 73 | if (a.charAt(i) != b.charAt(i)) { 74 | diffCount++; 75 | } 76 | } 77 | return diffCount == 1; 78 | } 79 | 80 | private static Map> getGraph(List dict) { 81 | Map> graph = new HashMap<>(); 82 | dict = dict.stream().distinct() 83 | .sorted(Comparator.comparing(String::length)).collect(toList()); 84 | Map> grouped = dict.stream() 85 | .collect(Collectors.groupingBy(String::length)); 86 | for (String word : dict) { 87 | if (!graph.containsKey(word)) { 88 | graph.put(word, new HashSet<>()); 89 | } 90 | List adjacent = grouped.get(word.length()).stream() 91 | .filter(x -> adjacent(word, x)).collect(toList()); 92 | graph.get(word).addAll(adjacent); 93 | } 94 | return graph; 95 | } 96 | 97 | public static void main(String[] args) throws IOException { 98 | String currentLine; 99 | List dict = new ArrayList<>(); 100 | while ((currentLine = reader.readLine()) != null && 101 | !currentLine.trim().equalsIgnoreCase("")) { 102 | dict.add(currentLine.trim()); 103 | } 104 | Map> graph = getGraph(dict); 105 | int line = 0; 106 | while ((currentLine = reader.readLine()) != null && 107 | !currentLine.trim().equalsIgnoreCase("")) { 108 | if (line > 0) { 109 | System.out.println(); 110 | } 111 | List input = stream(currentLine.trim().split(" ")) 112 | .filter(x -> !x.equals("")) 113 | .collect(toList()); 114 | List result = find(graph, input.get(0), input.get(1)); 115 | if (result == null) { 116 | System.out.println("No solution."); 117 | } else { 118 | result.forEach(System.out::println); 119 | } 120 | line++; 121 | } 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/Chapter3/FileFragmentation.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import static java.util.Comparator.comparing; 7 | import static java.util.stream.Collectors.toList; 8 | 9 | class FileFragmentation { 10 | private static final BufferedReader reader = 11 | new BufferedReader(new InputStreamReader(System.in)); 12 | 13 | private static boolean fit(List fragments, String candidate) { 14 | List temp = new ArrayList(fragments); 15 | for (int i = 1; i < candidate.length() && !temp.isEmpty(); ++i) { 16 | final int j = i; 17 | temp.removeIf(x -> x.equalsIgnoreCase(candidate.substring(0, j))); 18 | temp.removeIf(x -> x.equalsIgnoreCase(candidate.substring(j))); 19 | } 20 | return temp.isEmpty(); 21 | } 22 | 23 | private static String restore(List fragments) { 24 | fragments.sort(comparing(String::length)); 25 | String large = fragments.get(fragments.size() - 1); 26 | List smallest = fragments.stream().filter( 27 | x -> x.length() == fragments.get(0).length()).collect(toList()); 28 | for (String small : smallest) { 29 | if (fit(fragments, large + small)) { 30 | return large + small; 31 | } else if (fit(fragments, small + large)) { 32 | return small + large; 33 | } 34 | } 35 | return "Impossible"; 36 | } 37 | 38 | public static void main(String[] args) throws IOException { 39 | int n = Integer.parseInt(reader.readLine()); 40 | reader.readLine(); 41 | for (int i = 0; i < n; ++i) { 42 | List fragments = new ArrayList(); 43 | do { 44 | String s = reader.readLine(); 45 | if (s == null || s.equalsIgnoreCase("")) { 46 | break; 47 | } 48 | fragments.add(s); 49 | } while (true); 50 | System.out.println(restore(fragments)); 51 | if (i < n - 1) { 52 | System.out.println(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Chapter3/Fmt.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class Fmt { 8 | private static final BufferedReader reader = new BufferedReader( 9 | new InputStreamReader(System.in)); 10 | private static final int LINE_WIDTH = 72; 11 | 12 | private static List tokenize(String input) { 13 | List output = new ArrayList<>(); 14 | StringBuilder block = new StringBuilder(); 15 | int pos = 0; 16 | while (pos < input.length()) { 17 | if (input.charAt(pos) == ' ') { 18 | while (pos < input.length() && input.charAt(pos) == ' ') { 19 | block.append(input.charAt(pos)); 20 | pos++; 21 | } 22 | output.add(block.toString()); 23 | block = new StringBuilder(); 24 | } else if (input.charAt(pos) == '\n') { 25 | output.add(new String("\n")); 26 | pos++; 27 | } else { 28 | while (pos < input.length() && input.charAt(pos) != ' ' && 29 | input.charAt(pos) != '\n') { 30 | block.append(input.charAt(pos)); 31 | pos++; 32 | } 33 | output.add(block.toString()); 34 | block = new StringBuilder(); 35 | } 36 | } 37 | if (block.length() > 0) { 38 | output.add(block.toString()); 39 | } 40 | return output; 41 | } 42 | 43 | private static void flush(List line, StringBuilder output, 44 | boolean newline) { 45 | if (line.size() > 1 && line.get(line.size() - 1).startsWith(" ")) { 46 | line.remove(line.size() - 1); 47 | } 48 | 49 | StringBuilder lineStr = new StringBuilder(); 50 | for (String x : line) { 51 | lineStr.append(x); 52 | } 53 | 54 | output.append(lineStr).append(newline ? "\n" : ""); 55 | line.clear(); 56 | } 57 | 58 | private static String format(List tokens) { 59 | StringBuilder output = new StringBuilder(); 60 | List line = new ArrayList<>(); 61 | 62 | int i = 0; 63 | while (i < tokens.size()) { 64 | int currLength = line.stream().map(String::length) 65 | .reduce(0, Integer::sum).intValue(); 66 | String token = tokens.get(i); 67 | 68 | if (token.startsWith(" ")) { 69 | line.add(token); 70 | } else if (token.equals("\n")) { 71 | if (i + 1 < tokens.size()) { 72 | String next = tokens.get(i + 1); 73 | if (next.equals("\n") || next.startsWith(" ") || 74 | line.size() == 0 || (line.size() == 1 && 75 | line.get(0).startsWith(" "))) { 76 | flush(line, output, true); 77 | } else if (currLength + next.length() <= LINE_WIDTH) { 78 | line.add(" "); 79 | line.add(next); 80 | ++i; 81 | } else { 82 | flush(line, output, true); 83 | } 84 | } else { 85 | line.add(token); 86 | } 87 | } else if (currLength == 0 && token.length() > LINE_WIDTH) { 88 | line.add(token); 89 | if (i + 1 < tokens.size()) { 90 | flush(line, output, true); 91 | i++; 92 | } 93 | } else { 94 | if (currLength + token.length() > LINE_WIDTH) { 95 | flush(line, output, true); 96 | } 97 | line.add(token); 98 | } 99 | ++i; 100 | } 101 | 102 | if (line.size() > 0) { 103 | flush(line, output, false); 104 | } 105 | 106 | return output.toString(); 107 | } 108 | 109 | public static void main(String[] args) throws IOException { 110 | StringBuilder input = new StringBuilder(); 111 | while (true) { 112 | int c = reader.read(); 113 | if (c == -1) { 114 | break; 115 | } 116 | input.append((char) c); 117 | } 118 | System.out.print(format(tokenize(input.toString()))); 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/Chapter3/WERTYU.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class WERTYU { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | 9 | private final static String KEYS = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./"; 10 | private final static int[] map = new int[256]; 11 | 12 | static { 13 | for (int i = 0; i < KEYS.length(); ++i) { 14 | map[KEYS.charAt(i)] = i; 15 | } 16 | } 17 | 18 | private static String shift(String currentLine) { 19 | StringBuilder output = new StringBuilder(); 20 | for (int i = 0; i < currentLine.length(); ++i) { 21 | output.append(map[currentLine.charAt(i)] != 0 22 | ? KEYS.charAt(map[currentLine.charAt(i)] - 1) 23 | : currentLine.charAt(i)); 24 | } 25 | return output.toString(); 26 | } 27 | 28 | public static void main(String[] args) throws IOException { 29 | String currentLine; 30 | while ((currentLine = reader.readLine()) != null) { 31 | System.out.println(shift(currentLine)); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Chapter3/WheresWaldorf.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public class WheresWaldorf { 13 | private static final BufferedReader reader = new BufferedReader( 14 | new InputStreamReader(System.in)); 15 | 16 | private final int n; 17 | private final int m; 18 | private final char[][] table; 19 | 20 | public WheresWaldorf(int n, int m, char[][] table) { 21 | this.n = n; 22 | this.m = m; 23 | this.table = table; 24 | } 25 | 26 | private static final int[][] dir = new int[][] { 27 | { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 }, { 1, 1 }, { -1, -1 }, 28 | { -1, 1 }, { 1, -1 } 29 | }; 30 | 31 | public int[] find(String word) { 32 | for (int i = 0; i < n; ++i) { 33 | for (int j = 0; j < m; ++j) { 34 | for (int k = 0; k < dir.length; ++k) { 35 | if (check(dir[k][0], dir[k][1], i, j, word)) { 36 | return new int[] { i + 1, j + 1 }; 37 | } 38 | } 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | private boolean check(int di, int dj, int i, int j, String word) { 45 | if (word.length() == 1) { 46 | return table[i][j] == word.charAt(0); 47 | } 48 | int pos = 0; 49 | while (i >= 0 && i < n && j >= 0 && j < m && pos < word.length() && 50 | table[i][j] == word.charAt(pos)) { 51 | j += dj; 52 | i += di; 53 | pos++; 54 | } 55 | return pos == word.length(); 56 | } 57 | 58 | private static String toString(int[] arr) { 59 | return Arrays.stream(arr).mapToObj(String::valueOf) 60 | .collect(Collectors.joining(" ")); 61 | } 62 | 63 | public static void main(String[] args) throws IOException { 64 | int cases = Integer.parseInt(reader.readLine().trim()); 65 | reader.readLine(); 66 | for (int k = 0; k < cases; ++k) { 67 | List nm = stream(reader.readLine().trim().split(" ")) 68 | .filter(x -> !x.equals("")).map(Integer::parseInt) 69 | .collect(toList()); 70 | char[][] table = new char[nm.get(0)][nm.get(1)]; 71 | for (int i = 0; i < nm.get(0); ++i) { 72 | String currentLine = reader.readLine(); 73 | for (int j = 0; j < nm.get(1); ++j) { 74 | table[i][j] = currentLine.toLowerCase().charAt(j); 75 | } 76 | } 77 | int wordsCount = Integer.parseInt(reader.readLine().trim()); 78 | List words = new ArrayList<>(); 79 | for (int i = 0; i < wordsCount; ++i) { 80 | String currentLine = reader.readLine().toLowerCase(); 81 | words.add(currentLine); 82 | } 83 | WheresWaldorf ww = new WheresWaldorf(nm.get(0), nm.get(1), table); 84 | words.forEach(x -> System.out.println(toString(ww.find(x)))); 85 | if (k < cases - 1) { 86 | System.out.println(); 87 | reader.readLine(); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Chapter4/Bridge.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | import static java.util.stream.IntStream.range; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.PriorityQueue; 11 | import java.util.function.BiConsumer; 12 | import java.util.stream.Stream; 13 | 14 | 15 | class Bridge { 16 | private static final BufferedReader reader = 17 | new BufferedReader(new InputStreamReader(System.in)); 18 | private static final int LEFT_RIGHT = 0; 19 | private static final int RIGHT_LEFT = 1; 20 | 21 | private static void printResult(final List> result) { 22 | List lr = result.get(LEFT_RIGHT); 23 | List rl = result.get(RIGHT_LEFT); 24 | if (lr.size() == 1) { 25 | System.out.println(lr.get(0)); 26 | System.out.println(lr.get(0)); 27 | return; 28 | } 29 | 30 | int totalTime = range(0, lr.size()).filter(x -> (x + 1) % 2 == 0) 31 | .map(x -> lr.get(x)).sum() + 32 | rl.stream().mapToInt(Integer::intValue).sum(); 33 | System.out.println(totalTime); 34 | Stream.iterate(0, i -> i + 2).limit(lr.size() / 2).forEachOrdered(i -> { 35 | System.out.println(lr.get(i) + " " + lr.get(i + 1)); 36 | if (i / 2 < rl.size()) { 37 | System.out.println(rl.get(i / 2)); 38 | } 39 | }); 40 | } 41 | 42 | private static List> getStrategy(List input) { 43 | final List> output = Arrays 44 | .asList(new ArrayList(), new ArrayList()); 45 | 46 | if (input.size() == 1) { 47 | output.get(LEFT_RIGHT).add(input.get(0)); 48 | return output; 49 | } 50 | 51 | final PriorityQueue left = new PriorityQueue<>(); 52 | final PriorityQueue right = new PriorityQueue<>(); 53 | final BiConsumer, PriorityQueue> move = ( 54 | from, to) -> { 55 | if (!from.isEmpty()) { 56 | Integer v = from.remove(); 57 | to.add(v); 58 | output.get(from == left ? LEFT_RIGHT : RIGHT_LEFT).add(v); 59 | } 60 | }; 61 | 62 | left.addAll(input); 63 | 64 | while (!left.isEmpty()) { 65 | move.accept(right, left); 66 | move.andThen(move).accept(left, right); 67 | if (left.isEmpty()) { 68 | break; 69 | } 70 | 71 | move.accept(right, left); 72 | if (left.size() == 2) { 73 | move.andThen(move).accept(left, right); 74 | break; 75 | } 76 | 77 | Integer x1 = left.remove(); 78 | Integer x2 = right.peek(); 79 | Integer x4 = left.stream().max(Integer::compareTo).get(); 80 | left.remove(x4); 81 | Integer x3 = left.stream().max(Integer::compareTo).get(); 82 | left.remove(x3); 83 | int[] x = (2 * x2 <= x1 + x3) ? new int[] { x1, x3, x4 } 84 | : new int[] { x4, x1, x3 }; 85 | 86 | left.add(x[0]); 87 | output.get(LEFT_RIGHT).add(x[1]); 88 | output.get(LEFT_RIGHT).add(x[2]); 89 | right.add(x[1]); 90 | right.add(x[2]); 91 | } 92 | 93 | return output; 94 | } 95 | 96 | public static void main(String[] args) throws IOException { 97 | int n = Integer.valueOf(reader.readLine().trim()); 98 | reader.readLine(); 99 | for (int i = 0; i < n; ++i) { 100 | int count = Integer.valueOf(reader.readLine().trim()); 101 | List input = reader.lines().map(String::trim) 102 | .limit(count).map(Integer::parseInt).collect(toList()); 103 | printResult(getStrategy(input)); 104 | if (i < n - 1) { 105 | reader.readLine(); 106 | System.out.println(); 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Chapter4/LongestNap.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.time.LocalTime; 5 | import java.time.format.DateTimeFormatter; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public class LongestNap { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | private static final int START = 0; 15 | private static final int END = 1; 16 | 17 | private final static Pattern pattern = Pattern 18 | .compile("(\\d\\d:\\d\\d)\\s+(\\d\\d:\\d\\d)"); 19 | 20 | private final static DateTimeFormatter formatter = DateTimeFormatter 21 | .ofPattern("HH:mm"); 22 | 23 | private static final LocalTime[] parseTime(String line) { 24 | Matcher matcher = pattern.matcher(line); 25 | matcher.find(); 26 | return new LocalTime[] { 27 | LocalTime.parse(matcher.group(1), formatter), 28 | LocalTime.parse(matcher.group(2), formatter) 29 | }; 30 | } 31 | 32 | private static final List combine( 33 | List intervals) { 34 | List intr = new ArrayList<>(intervals); 35 | intr.sort((x, y) -> x[START].compareTo(y[START])); 36 | List res = new ArrayList<>(); 37 | 38 | while (!intr.isEmpty()) { 39 | LocalTime[] curr = intr.remove(0); 40 | while (!intr.isEmpty()) { 41 | if (intr.get(0)[START].isBefore(curr[END]) || 42 | intr.get(0)[START].equals(curr[END])) { 43 | LocalTime[] next = intr.remove(0); 44 | if (curr[END].isAfter(next[START]) || 45 | curr[END].equals(next[START])) { 46 | if (curr[END].isBefore(next[END])) { 47 | curr[END] = next[END]; 48 | } 49 | } 50 | } else { 51 | break; 52 | } 53 | } 54 | res.add(curr); 55 | } 56 | 57 | return res; 58 | } 59 | 60 | private static LocalTime[] findLongest(List intervals) { 61 | if (intervals.size() == 0) { 62 | return new LocalTime[] { LocalTime.of(10, 0), 63 | LocalTime.of(8, 0) }; 64 | } 65 | 66 | LocalTime earliest = intervals.get(0)[START]; 67 | LocalTime latest = intervals.get(intervals.size() - 1)[END]; 68 | 69 | long i1 = earliest.toSecondOfDay() - 70 | LocalTime.of(10, 0).toSecondOfDay(); 71 | long i2 = LocalTime.of(18, 0).toSecondOfDay() - latest.toSecondOfDay(); 72 | 73 | LocalTime[] result = (i1 < i2) 74 | ? new LocalTime[] { latest, LocalTime.ofSecondOfDay(i2) } 75 | : new LocalTime[] { LocalTime.of(10, 0), 76 | LocalTime.ofSecondOfDay(i1) }; 77 | 78 | for (int i = 0; i < intervals.size() - 1; ++i) { 79 | long interval = intervals.get(i + 1)[START].toSecondOfDay() - 80 | intervals.get(i)[END].toSecondOfDay(); 81 | if (interval >= result[1].toSecondOfDay()) { 82 | boolean same = interval == result[1].toSecondOfDay(); 83 | result[1] = LocalTime.ofSecondOfDay(interval); 84 | if (same && result[0].isAfter(intervals.get(i)[END]) || !same) { 85 | result[0] = intervals.get(i)[END]; 86 | } 87 | } 88 | } 89 | 90 | return result; 91 | } 92 | 93 | public static void main(String[] args) throws IOException { 94 | String currentLine; 95 | int d = 1; 96 | while ((currentLine = reader.readLine()) != null) { 97 | int appointments = Integer.parseInt(currentLine.trim()); 98 | List intervals = new ArrayList<>(); 99 | for (int i = 0; i < appointments; ++i) { 100 | intervals.add(parseTime(reader.readLine())); 101 | } 102 | LocalTime[] result = findLongest(combine(intervals)); 103 | System.out.println("Day #" + d + ": the longest nap starts at " + 104 | formatter.format(result[START]) + " and will last for " + 105 | ((result[1].getHour() > 0) 106 | ? result[1].getHour() + " hours and " : "") + 107 | result[1].getMinute() + " minutes."); 108 | d++; 109 | } 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/Chapter4/ShellSort.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | class ShellSort { 10 | private static final BufferedReader reader = 11 | new BufferedReader(new InputStreamReader(System.in)); 12 | 13 | private static List getStrategy(List input, List target) { 14 | int i = input.size() - 1; 15 | int j = target.size() - 1; 16 | while (i >= 0 && j >= 0) { 17 | while (j >= 0 && !target.get(i).equals(input.get(j))) { 18 | j--; 19 | } 20 | if (j < 0) { 21 | break; 22 | } 23 | i--; 24 | j--; 25 | } 26 | List output = target.subList(0, i + 1); 27 | Collections.reverse(output); 28 | return output; 29 | } 30 | 31 | public static void main(String[] args) throws IOException { 32 | int n = Integer.valueOf(reader.readLine().trim()); 33 | for (int i = 0; i < n; ++i) { 34 | int count = Integer.valueOf(reader.readLine().trim()); 35 | List input = reader.lines().limit(count).collect(toList()); 36 | List target = reader.lines().limit(count).collect(toList()); 37 | getStrategy(input, target).forEach(System.out::println); 38 | System.out.println(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Chapter4/ShoemakersProblem.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class ShoemakersProblem { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | 15 | public static class Job implements Comparable { 16 | int start; 17 | int fine; 18 | int index; 19 | 20 | public Job(int index, int start, int fine) { 21 | this.index = index; 22 | this.start = start; 23 | this.fine = fine; 24 | } 25 | 26 | @Override 27 | public int compareTo(Job o) { 28 | return Integer.compare(o.fine * start, fine * o.start); 29 | } 30 | } 31 | 32 | public static void main(String[] args) 33 | throws NumberFormatException, IOException { 34 | int n = Integer.parseInt(reader.readLine().trim()); 35 | for (int i = 0; i < n; ++i) { 36 | reader.readLine(); 37 | int count = Integer.parseInt(reader.readLine().trim()); 38 | Job[] jobs = new Job[count]; 39 | for (int j = 0; j < count; ++j) { 40 | List input = stream( 41 | reader.readLine().trim().split(" ")) 42 | .filter(x -> !x.equals("")) 43 | .map(Integer::parseInt) 44 | .collect(toList()); 45 | jobs[j] = new Job(j, input.get(0), input.get(1)); 46 | } 47 | Arrays.sort(jobs); 48 | System.out.println(Arrays.stream(jobs).map(x -> x.index + 1) 49 | .map(String::valueOf) 50 | .collect(Collectors.joining(" "))); 51 | if (i < n - 1) { 52 | System.out.println(); 53 | } 54 | } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/Chapter4/StacksOfFlapjacks.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public class StacksOfFlapjacks { 13 | private static final BufferedReader reader = new BufferedReader( 14 | new InputStreamReader(System.in)); 15 | 16 | private static int max(List input, int skip) { 17 | int index = -1; 18 | int max = Integer.MIN_VALUE; 19 | for (int i = skip; i < input.size(); ++i) { 20 | if (max < input.get(i)) { 21 | index = i; 22 | max = input.get(i); 23 | } 24 | } 25 | return index; 26 | } 27 | 28 | private static List solve(List input) { 29 | List inputCopy = new ArrayList<>(input); 30 | Collections.reverse(inputCopy); 31 | List flips = new ArrayList<>(); 32 | int sorted = 0; 33 | 34 | while (sorted < inputCopy.size()) { 35 | int index = max(inputCopy, sorted); 36 | if (index != sorted) { 37 | flips.add(index + 1); 38 | flips.add(sorted + 1); 39 | Collections.reverse(inputCopy.subList(index, inputCopy.size())); 40 | Collections 41 | .reverse(inputCopy.subList(sorted, inputCopy.size())); 42 | } 43 | sorted++; 44 | } 45 | flips.add(0); 46 | return flips; 47 | } 48 | 49 | public static void main(String[] args) throws IOException { 50 | String currentLine; 51 | while ((currentLine = reader.readLine()) != null) { 52 | List input = stream(currentLine.trim().split(" ")) 53 | .filter(x -> !x.equals("")).map(Integer::parseInt) 54 | .collect(toList()); 55 | System.out.println(currentLine); 56 | System.out.println(solve(input).stream().map(x -> x.toString()) 57 | .collect(Collectors.joining(" "))); 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/Chapter4/VitosFamily.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | public class VitosFamily { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | private static int solve(List input) { 15 | Collections.sort(input); 16 | int median = 0; 17 | 18 | if (input.size() % 2 == 0) { 19 | int p = input.size() / 2 - 1; 20 | median = (input.get(p) + input.get(p + 1)) / 2; 21 | } else { 22 | int p = input.size() / 2; 23 | median = (input.get(p)); 24 | } 25 | 26 | int sum = 0; 27 | for (Integer v : input) { 28 | sum += Math.abs(v - median); 29 | } 30 | return sum; 31 | } 32 | 33 | public static void main(String[] args) throws IOException { 34 | int cases = Integer.parseInt(reader.readLine().trim()); 35 | for (int i = 0; i < cases; ++i) { 36 | List input = stream(reader.readLine().trim().split(" ")) 37 | .filter(x -> !x.equals("")).map(Integer::parseInt) 38 | .collect(toList()); 39 | System.out.println(solve(input.subList(1, input.size()))); 40 | } 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/Chapter5/MultiplicationGame.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | 8 | class MultiplicationGame { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | private static int solve(long p, long n, int t, 13 | List> memo) { 14 | if (p >= n) { 15 | return t - 1; 16 | } 17 | 18 | int s = t % 2; 19 | for (int i = 9; i >= 2; --i) { 20 | int result = 0; 21 | long next = p * i; 22 | if (memo.get(s).containsKey(next)) { 23 | result = memo.get(s).get(next); 24 | } else { 25 | result = solve(next, n, t + 1, memo); 26 | memo.get(s).put(next, result); 27 | } 28 | if (result % 2 == t % 2) { 29 | return result; 30 | } 31 | } 32 | 33 | return t + 1; 34 | } 35 | 36 | public static void main(String[] args) throws IOException { 37 | String currentLine; 38 | while ((currentLine = reader.readLine()) != null) { 39 | long input = Long.parseLong(currentLine.trim()); 40 | List> memo = new ArrayList<>(); 41 | memo.add(new HashMap()); 42 | memo.add(new HashMap()); 43 | System.out.println( 44 | solve(1, input, 1, memo) % 2 == 0 ? "Ollie wins." 45 | : "Stan wins."); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Chapter5/Ones.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | class Ones { 6 | private static final BufferedReader reader = 7 | new BufferedReader(new InputStreamReader(System.in)); 8 | 9 | private static int calculate(int n) { 10 | if (n == 1) { 11 | return 1; 12 | } 13 | int l = 0; 14 | int r = 0; 15 | do { 16 | r = (r * 10 + 1) % n; 17 | l++; 18 | } while (r > 0); 19 | return l; 20 | } 21 | 22 | public static void main(String[] args) throws IOException { 23 | reader.lines().map(Integer::parseInt) 24 | .map(Ones::calculate) 25 | .forEach(System.out::println); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Chapter5/PairsumoniousNumbers.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.Arrays; 8 | import java.util.BitSet; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public class PairsumoniousNumbers { 13 | private static final BufferedReader reader = new BufferedReader( 14 | new InputStreamReader(System.in)); 15 | private final static int[] IMPOSSIBLE = new int[0]; 16 | 17 | private enum Result { 18 | success, failure, overflow 19 | }; 20 | 21 | private final int n; 22 | private final int[] v; 23 | private final BitSet excluded; 24 | 25 | public int[] getSolution() { 26 | int[] partialResult = new int[n]; 27 | 28 | int[] bounds = new int[] { Integer.MAX_VALUE, v[v.length - 1] }; 29 | for (int i = 0; i < v.length; ++i) { 30 | for (int j = i + 1; j < v.length; j++) { 31 | bounds[0] = Math.min(bounds[0], v[i] - v[j]); 32 | } 33 | } 34 | 35 | if (bounds[0] > bounds[1]) { 36 | int t = bounds[0]; 37 | bounds[0] = bounds[1]; 38 | bounds[1] = t; 39 | } 40 | 41 | if (bounds[1] < 0) { 42 | bounds[1] = 0; 43 | } 44 | 45 | for (int i = bounds[0]; i < bounds[1]; ++i) { 46 | partialResult = new int[n]; 47 | partialResult[0] = i; 48 | int[] result = search(partialResult, 0, 0); 49 | if (result != IMPOSSIBLE) { 50 | Arrays.sort(result); 51 | return result; 52 | } 53 | } 54 | return IMPOSSIBLE; 55 | } 56 | 57 | PairsumoniousNumbers(List input) { 58 | n = input.get(0); 59 | v = new int[input.size() - 1]; 60 | for (int i = 1; i < input.size(); ++i) { 61 | v[i - 1] = input.get(i); 62 | } 63 | Arrays.sort(v); 64 | excluded = new BitSet(n); 65 | } 66 | 67 | private Result verify(int upTo, int[] solution) { 68 | excluded.clear(); 69 | for (int i = 0; i < upTo; ++i) { 70 | for (int j = i + 1; j < upTo; ++j) { 71 | int currValue = solution[i] + solution[j]; 72 | if (currValue > v[v.length - 1]) { 73 | return Result.overflow; 74 | } 75 | 76 | int p = Arrays.binarySearch(v, currValue); 77 | if (p < 0) { 78 | return Result.failure; 79 | } 80 | while (p > 0 && v[p] == v[p - 1]) { 81 | p--; 82 | } 83 | while (p < v.length - 1 && excluded.get(p) && 84 | v[p] == v[p + 1]) { 85 | p++; 86 | } 87 | if (p == v.length || excluded.get(p)) { 88 | return Result.failure; 89 | } 90 | excluded.set(p); 91 | } 92 | } 93 | 94 | for (int i = 0; i < upTo - 1; ++i) { 95 | if (!excluded.get(i)) { 96 | return Result.failure; 97 | } 98 | } 99 | 100 | return Result.success; 101 | } 102 | 103 | private int[] search(int[] partialSolution, int last, int pos) { 104 | for (int i = pos; i < v.length; ++i) { 105 | partialSolution[last + 1] = v[i] - partialSolution[0]; 106 | Result verificationResult = verify(last + 2, partialSolution); 107 | if (verificationResult == Result.success) { 108 | if (last + 1 < n - 1) { 109 | int[] solution = search(partialSolution, last + 1, i + 1); 110 | if (solution != IMPOSSIBLE) { 111 | return solution; 112 | } 113 | } else { 114 | return partialSolution; 115 | } 116 | } else if (verificationResult == Result.overflow) { 117 | break; 118 | } 119 | } 120 | return IMPOSSIBLE; 121 | } 122 | 123 | private static String toString(int[] arr) { 124 | return Arrays.stream(arr).mapToObj(String::valueOf) 125 | .collect(Collectors.joining(" ")); 126 | } 127 | 128 | public static void main(String[] args) throws IOException { 129 | String currentLine; 130 | while ((currentLine = reader.readLine()) != null) { 131 | List input = stream(currentLine.trim().split(" ")) 132 | .filter(x -> !x.equals("")).map(Integer::parseInt) 133 | .collect(toList()); 134 | int[] solution = new PairsumoniousNumbers(input).getSolution(); 135 | System.out 136 | .println(solution == IMPOSSIBLE ? "Impossible" 137 | : toString(solution)); 138 | } 139 | } 140 | 141 | } 142 | 143 | -------------------------------------------------------------------------------- /src/Chapter5/PolynomialCoefficients.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | 11 | public class PolynomialCoefficients { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | 15 | private static List expand(int n) { 16 | List res = new ArrayList(); 17 | for (int i = n; i > 0; --i) { 18 | res.add(i); 19 | } 20 | return res; 21 | } 22 | 23 | private static long calculate(int n, List v) { 24 | List numerator = expand(n); 25 | List denominator = new ArrayList<>(); 26 | v.stream().filter(x -> x > 0) 27 | .forEach(x -> denominator.addAll(expand(x))); 28 | Iterator it = denominator.iterator(); 29 | while (it.hasNext()) { 30 | if (numerator.remove(it.next())) { 31 | it.remove(); 32 | } 33 | } 34 | return numerator.stream().reduce(1, Math::multiplyExact).intValue() / 35 | denominator.stream().reduce(1, Math::multiplyExact).intValue(); 36 | } 37 | 38 | private static List readList(String input) { 39 | return stream(input.trim().split(" ")) 40 | .filter(x -> !x.equals("")).map(Integer::parseInt) 41 | .collect(toList()); 42 | } 43 | 44 | public static void main(String[] args) throws IOException { 45 | String currentLine; 46 | while ((currentLine = reader.readLine()) != null) { 47 | List nk = readList(currentLine); 48 | List v = readList(reader.readLine()); 49 | System.out.println(calculate(nk.get(0), v)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Chapter5/PrimaryArithmetic.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.util.Arrays; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | 10 | public class PrimaryArithmetic { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | private static int[] asArray(String input, int pad) { 15 | int[] a = new int[input.length() + pad]; 16 | for (int i = 0; i < input.length(); ++i) { 17 | a[i] = input.charAt(input.length() - i - 1) - '0'; 18 | } 19 | return a; 20 | } 21 | 22 | public static int count(List input) { 23 | int[] a = asArray(input.get(0), 0); 24 | int[] b = asArray(input.get(1), 25 | input.get(0).length() - input.get(1).length()); 26 | int carry = 0; 27 | int count = 0; 28 | for (int i = 0; i < a.length; ++i) { 29 | int c = a[i] + b[i] + carry; 30 | if (c >= 10) { 31 | carry = 1; 32 | count++; 33 | } else { 34 | carry = 0; 35 | } 36 | } 37 | return count; 38 | } 39 | 40 | public static String toMessage(int count) { 41 | if (count == 0) { 42 | return "No carry operation."; 43 | } else if (count == 1) { 44 | return "1 carry operation."; 45 | } else { 46 | return count + " carry operations."; 47 | } 48 | } 49 | 50 | public static void main(String[] args) throws IOException { 51 | String currentLine; 52 | while ((currentLine = reader.readLine()) != null) { 53 | List input = Arrays 54 | .stream(currentLine.trim().split(" ")) 55 | .filter(x -> !x.equals(" ")) 56 | .sorted(Comparator.comparing(String::length).reversed()) 57 | .collect(toList()); 58 | if (input.get(0).equals("0") && input.get(1).equals("0")) { 59 | break; 60 | } 61 | System.out.println(toMessage(count(input))); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Chapter5/ReverseAndAdd.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | class ReverseAndAdd { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | 9 | private static long reverse(long value) { 10 | long reversed = 0; 11 | while (value > 9) { 12 | reversed = reversed * 10 + (value % 10); 13 | value /= 10; 14 | } 15 | reversed = reversed * 10 + value; 16 | return reversed; 17 | } 18 | 19 | private static boolean isPalindrome(long value) { 20 | return value == reverse(value); 21 | } 22 | 23 | public static long[] calculate(long value) { 24 | int count = 0; 25 | do { 26 | value = value + reverse(value); 27 | count++; 28 | } while (!isPalindrome(value)); 29 | return new long[] { count, value }; 30 | } 31 | 32 | public static void main(String[] args) throws IOException { 33 | int n = Integer.parseInt(reader.readLine().trim()); 34 | for (int i = 0; i < n; ++i) { 35 | long v = Integer.parseInt(reader.readLine().trim()); 36 | long[] res = calculate(v); 37 | System.out.println(res[0] + " " + res[1]); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Chapter5/TheArcheologistsDilemma.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigDecimal; 5 | 6 | public class TheArcheologistsDilemma { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | private static long calculate(long v) { 11 | long n = BigDecimal.valueOf(v).precision() + 1; 12 | final double left = Math.log10(v); 13 | final double right = Math.log10(v + 1); 14 | final double log10_2 = Math.log10(2); 15 | while (true) { 16 | long m = (long) Math.floor((left / log10_2) + n / log10_2); 17 | while (left + n > (log10_2 * m)) { 18 | m++; 19 | } 20 | if (right + n > (log10_2 * m)) { 21 | return m; 22 | } 23 | n++; 24 | } 25 | } 26 | 27 | public static void main(String[] args) throws IOException { 28 | String currentLine; 29 | while ((currentLine = reader.readLine()) != null) { 30 | System.out.println(calculate(Long.parseLong(currentLine.trim()))); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Chapter5/TheSternBrocotNumberSystem.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | public class TheSternBrocotNumberSystem { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | private static int gcd(int a, int b) { 14 | while (b != 0) { 15 | int t = b; 16 | b = a % b; 17 | a = t; 18 | } 19 | return a; 20 | } 21 | 22 | private static String get(int a, int b) { 23 | int gcd = gcd(a, b); 24 | a = a / gcd; 25 | b = b / gcd; 26 | 27 | int[] l = new int[] { 0, 1 }; 28 | int[] m = new int[] { 1, 1 }; 29 | int[] r = new int[] { 1, 0 }; 30 | 31 | StringBuilder result = new StringBuilder(); 32 | while (true) { 33 | int cmp = Integer.compare(a * m[1], b * m[0]); 34 | if (cmp == -1) { 35 | r = new int[] { m[0], m[1] }; 36 | m = new int[] { l[0] + m[0], l[1] + m[1] }; 37 | result.append("L"); 38 | } else if (cmp == 1) { 39 | l = new int[] { m[0], m[1] }; 40 | m = new int[] { r[0] + m[0], r[1] + m[1] }; 41 | result.append("R"); 42 | } else { 43 | break; 44 | } 45 | } 46 | return result.toString(); 47 | } 48 | 49 | private static List readList(String input) { 50 | return stream(input.trim().split(" ")) 51 | .filter(x -> !x.equals("")).map(Integer::parseInt) 52 | .collect(toList()); 53 | } 54 | 55 | public static void main(String[] args) throws IOException { 56 | String currentLine; 57 | while ((currentLine = reader.readLine()) != null) { 58 | List ab = readList(currentLine); 59 | if (ab.get(0) == 1 && ab.get(1) == 1) { 60 | break; 61 | } 62 | System.out.println(get(ab.get(0), ab.get(1))); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Chapter6/CompleteTreeLabeling.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.math.BigInteger; 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | class CompleteTreeLabeling { 13 | private static final BufferedReader reader = new BufferedReader( 14 | new InputStreamReader(System.in)); 15 | 16 | private static List expand(int n, int upto) { 17 | List res = new ArrayList(); 18 | for (int i = n; i > upto; --i) { 19 | res.add(BigInteger.valueOf(i)); 20 | } 21 | return res; 22 | } 23 | 24 | private static BigInteger mult(List l) { 25 | return l.stream().reduce(BigInteger.ONE, (x, y) -> x.multiply(y)); 26 | } 27 | 28 | private static BigInteger choose(int n, int k) { 29 | List numerator = expand(n, (n - k)); 30 | List denominator = expand(k, 0); 31 | Iterator it = denominator.iterator(); 32 | while (it.hasNext()) { 33 | if (numerator.remove(it.next())) { 34 | it.remove(); 35 | } 36 | } 37 | return mult(numerator).divide(mult(denominator)); 38 | } 39 | 40 | private static BigInteger count(BigInteger base, int treeSize, int k, 41 | int h) { 42 | if (h == 1) { 43 | return base; 44 | } 45 | int subtreeSize = (treeSize - 1) / k; 46 | BigInteger subtreeCount = count(base, subtreeSize, k, h - 1); 47 | BigInteger count = base; 48 | for (int i = subtreeSize - 1; i <= treeSize - 2; i += subtreeSize) { 49 | count = count.multiply(subtreeCount) 50 | .multiply(choose(i, subtreeSize - 1)); 51 | } 52 | return count; 53 | } 54 | 55 | private static BigInteger solve(int k, int h) { 56 | if (k == 1) { 57 | return BigInteger.ONE; 58 | } 59 | int pow = 1; 60 | for (int i = 0; i < h + 1; ++i) { 61 | pow *= k; 62 | } 63 | return count(mult(expand(k, 0)), (pow - 1) / (k - 1), k, h); 64 | } 65 | 66 | public static void main(String[] args) throws IOException { 67 | String currentLine; 68 | while ((currentLine = reader.readLine()) != null) { 69 | List input = stream(currentLine.trim().split(" ")) 70 | .filter(x -> !x.equals("")).map(Integer::parseInt) 71 | .collect(toList()); 72 | System.out.println(solve(input.get(0), input.get(1))); 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/Chapter6/Counting.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigInteger; 5 | 6 | public class Counting { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | private static BigInteger count(int n) { 11 | final BigInteger two = BigInteger.valueOf(2); 12 | if (n == 1) { 13 | return two; 14 | } else if (n == 0) { 15 | return BigInteger.ONE; 16 | } else if (n < 0) { 17 | return BigInteger.ZERO; 18 | } 19 | 20 | BigInteger[] prev = new BigInteger[] { BigInteger.ZERO, BigInteger.ONE, 21 | two }; 22 | 23 | for (int i = 1; i < n; ++i) { 24 | BigInteger next = prev[2].multiply(two).add(prev[1]).add(prev[0]); 25 | prev[0] = prev[1]; 26 | prev[1] = prev[2]; 27 | prev[2] = next; 28 | } 29 | 30 | return prev[2]; 31 | } 32 | 33 | public static void main(String[] args) 34 | throws NumberFormatException, IOException { 35 | String currentLine; 36 | while ((currentLine = reader.readLine()) != null) { 37 | System.out.println(count(Integer.parseInt(currentLine.trim()))); 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/Chapter6/Expressions.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.math.BigInteger; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | public class Expressions { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | private static final BigInteger[][] memo = new BigInteger[151][151]; 15 | 16 | public static BigInteger c(int n, int d) { 17 | if (d == 1 || n == 0) { 18 | return BigInteger.ONE; 19 | } 20 | 21 | if (memo[n][d] != null) { 22 | return memo[n][d]; 23 | } 24 | 25 | BigInteger v = BigInteger.ZERO; 26 | for (int i = 0; i <= n - 1; ++i) { 27 | BigInteger v1 = c(i, d - 1); 28 | BigInteger v2 = c(n - i - 1, d); 29 | v = v1.multiply(v2).add(v); 30 | } 31 | 32 | memo[n][d] = v; 33 | return v; 34 | } 35 | 36 | public static BigInteger solve(int n, int d) { 37 | if (n % 2 != 0) { 38 | return BigInteger.ZERO; 39 | } 40 | for (int i = 0; i < memo.length; ++i) { 41 | Arrays.fill(memo[i], null); 42 | } 43 | return c(n / 2, d).subtract(c(n / 2, d - 1)); 44 | } 45 | 46 | public static void main(String[] args) throws IOException { 47 | String currentLine; 48 | while ((currentLine = reader.readLine()) != null && 49 | !currentLine.trim().isEmpty()) { 50 | List input = stream(currentLine.trim().split(" ")) 51 | .filter(x -> !x.equals("")).map(Integer::parseInt) 52 | .collect(toList()); 53 | System.out.println(solve(input.get(0), input.get(1))); 54 | } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/Chapter6/HowManyFibs.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.math.BigInteger; 8 | import java.util.List; 9 | 10 | public class HowManyFibs { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | public static void main(String[] args) throws IOException { 15 | String currentLine; 16 | while ((currentLine = reader.readLine()) != null) { 17 | List range = stream(currentLine.trim().split(" ")) 18 | .filter(x -> !x.equals("")).map(BigInteger::new) 19 | .collect(toList()); 20 | if (range.get(0).equals(BigInteger.ZERO) && 21 | range.get(1).equals(BigInteger.ZERO)) { 22 | break; 23 | } 24 | BigInteger fn2 = BigInteger.ZERO; 25 | BigInteger fn1 = BigInteger.ONE; 26 | BigInteger fn = fn2.add(fn1); 27 | long counter = 0; 28 | while (fn.compareTo(range.get(1)) <= 0) { 29 | if (fn.compareTo(range.get(0)) >= 0) { 30 | counter++; 31 | } 32 | fn2 = fn1; 33 | fn1 = fn; 34 | fn = fn1.add(fn2); 35 | } 36 | System.out.println(counter); 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/Chapter6/HowManyPiecesOfLand.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigInteger; 5 | 6 | public class HowManyPiecesOfLand { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | 10 | private static BigInteger calculate(BigInteger v) { 11 | BigInteger t1 = v.multiply(v.subtract(BigInteger.ONE)) 12 | .divide(BigInteger.valueOf(2)); 13 | BigInteger t2 = v.multiply(v.subtract(BigInteger.ONE)) 14 | .multiply(v.subtract(BigInteger.valueOf(2))) 15 | .multiply(v.subtract(BigInteger.valueOf(3))) 16 | .divide(BigInteger.valueOf(4 * 3 * 2)); 17 | return BigInteger.ONE.add(t2).add(t1); 18 | } 19 | 20 | public static void main(String[] args) 21 | throws NumberFormatException, IOException { 22 | int n = Integer.parseInt(reader.readLine().trim()); 23 | for (int i = 0; i < n; ++i) { 24 | System.out.println( 25 | calculate(new BigInteger(reader.readLine().trim()))); 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/Chapter6/SelfDescribingSequence.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | class SelfDescribingSequence { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | private List seq = new ArrayList<>(); 13 | private static final long limit = 2_000_000_000L; 14 | 15 | SelfDescribingSequence() { 16 | seq.add(new Tuple(1, 1)); 17 | seq.add(new Tuple(2, 3)); 18 | seq.add(new Tuple(4, 5)); 19 | int tupleIndex = 2; 20 | boolean cont = true; 21 | do { 22 | Tuple currTuple = seq.get(tupleIndex); 23 | for (long i = currTuple.v1; i <= currTuple.v2; ++i) { 24 | Tuple lastTuple = seq.get(seq.size() - 1); 25 | if (lastTuple.v1 >= limit) { 26 | cont = false; 27 | break; 28 | } 29 | seq.add(new Tuple(lastTuple.v2 + 1, lastTuple.v2 + tupleIndex + 1)); 30 | } 31 | tupleIndex++; 32 | } while (cont); 33 | } 34 | 35 | static class Tuple { 36 | private long v1; 37 | private long v2; 38 | 39 | public Tuple(long v1, long v2) { 40 | this.v1 = v1; 41 | this.v2 = v2; 42 | } 43 | } 44 | 45 | public long get(long n) { 46 | int i = Collections.binarySearch(seq, new Tuple(n + 1, 0), 47 | (x, y) -> Long.compare(x.v1, y.v1)); 48 | if (i < 0) { 49 | i = Math.abs(i + 1); 50 | } 51 | return i; 52 | } 53 | 54 | public static void main(String[] args) throws IOException { 55 | SelfDescribingSequence g = new SelfDescribingSequence(); 56 | String currentLine; 57 | while ((currentLine = reader.readLine()) != null && 58 | !currentLine.trim().equalsIgnoreCase("")) { 59 | long n = Long.parseLong(currentLine.trim()); 60 | if (n == 0) { 61 | break; 62 | } 63 | System.out.println(g.get(n)); 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/Chapter6/Steps.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | class Steps { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | public static long getLength(long limit) { 14 | long n = 1; 15 | while (n * (1 + n) <= limit) { 16 | n++; 17 | } 18 | if (n * (1 + n) > limit) { 19 | n--; 20 | } 21 | return n; 22 | } 23 | 24 | public static long getSteps(long n, long limit) { 25 | long sum = n * (1 + n); 26 | long steps = n * 2; 27 | long i = n; 28 | short j = 0; 29 | 30 | while (sum > limit) { 31 | sum -= i; 32 | steps--; 33 | if (j == 1) { 34 | j = 0; 35 | i--; 36 | } 37 | j++; 38 | } 39 | 40 | while (sum < limit) { 41 | while (sum + i <= limit) { 42 | sum += i; 43 | steps++; 44 | } 45 | if (i > 1) { 46 | i--; 47 | } 48 | } 49 | return steps; 50 | } 51 | 52 | public static long solve(long x, long y) { 53 | long limit = y - x; 54 | if (limit <= 1) { 55 | return limit; 56 | } 57 | long len = getLength(limit); 58 | return Math.min(getSteps(len, limit), getSteps(len + 1, limit)); 59 | } 60 | 61 | public static void main(String[] args) throws IOException { 62 | int n = Integer.parseInt(reader.readLine().trim()); 63 | for (int i = 0; i < n; ++i) { 64 | List input = stream(reader.readLine().trim().split(" ")) 65 | .filter(x -> !x.equals("")).map(Integer::parseInt) 66 | .collect(toList()); 67 | System.out.println(solve(input.get(0), input.get(1))); 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/Chapter6/ThePriestMathematician.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigInteger; 5 | 6 | class ThePriestMathematician { 7 | private static final BufferedReader reader = new BufferedReader( 8 | new InputStreamReader(System.in)); 9 | private static final BigInteger TWO = BigInteger.valueOf(2); 10 | private static final BigInteger ONE = BigInteger.ONE; 11 | private static final BigInteger ZERO = BigInteger.ZERO; 12 | 13 | public static BigInteger[] generate() { 14 | BigInteger[] hanoi = new BigInteger[10001]; 15 | hanoi[0] = ZERO; 16 | hanoi[1] = ONE; 17 | for (int i = 2, k = 1; i <= 10000; ++i) { 18 | BigInteger n1 = TWO.pow(i - k).subtract(ONE) 19 | .add(hanoi[k].multiply(TWO)); 20 | BigInteger n2 = hanoi[k + 1] != null ? TWO.pow(i - (k + 1)) 21 | .subtract(ONE).add(hanoi[k + 1].multiply(TWO)) 22 | : null; 23 | if (n2 != null && n2.compareTo(n1) == -1) { 24 | k++; 25 | hanoi[i] = n2; 26 | } else { 27 | hanoi[i] = n1; 28 | } 29 | } 30 | return hanoi; 31 | } 32 | 33 | public static void main(String[] args) throws IOException { 34 | BigInteger[] hanoi = generate(); 35 | String currentLine = null; 36 | while ((currentLine = reader.readLine()) != null && 37 | !currentLine.trim().equals("")) { 38 | System.out.println(hanoi[Integer.parseInt(currentLine.trim())]); 39 | } 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/Chapter7/CarmichaelNumbers.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.math.BigInteger; 5 | import java.util.Arrays; 6 | import java.util.BitSet; 7 | 8 | class CarmichaelNumbers { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | private final int[] primes; 13 | private final static int MAX_PRIMES = 66000; 14 | 15 | CarmichaelNumbers() { 16 | BitSet bits = new BitSet(MAX_PRIMES); 17 | for (int i = 2; i < Math.sqrt(MAX_PRIMES); ++i) { 18 | if (!bits.get(i)) { 19 | int k = 0; 20 | int ii = i * i; 21 | int j = ii + k * i; 22 | while (j < MAX_PRIMES) { 23 | bits.set(j); 24 | k++; 25 | j = ii + k * i; 26 | } 27 | } 28 | } 29 | 30 | int size = 0; 31 | for (int i = 2; i < bits.length(); ++i) { 32 | if (!bits.get(i)) { 33 | size++; 34 | } 35 | } 36 | 37 | int j = 0; 38 | primes = new int[size]; 39 | for (int i = 2; i < bits.length(); ++i) { 40 | if (!bits.get(i)) { 41 | primes[j++] = i; 42 | } 43 | } 44 | } 45 | 46 | public long modPow(long b, long e, long m) { 47 | if (m == 1) { 48 | return 0; 49 | } 50 | 51 | long result = 1; 52 | b = b % m; 53 | while (e > 0) { 54 | if (e % 2 == 1) { 55 | result = (result * b) % m; 56 | } 57 | e = e >> 1; 58 | b = (b * b) % m; 59 | } 60 | return result; 61 | } 62 | 63 | public boolean isCarmichael(int n) { 64 | if (Arrays.binarySearch(primes, n) >= 0) { 65 | return false; 66 | } 67 | 68 | for (int i = 2; i < n; ++i) { 69 | if (modPow(i, n, n) != i) { 70 | return false; 71 | } 72 | } 73 | return true; 74 | } 75 | 76 | public static void main(String[] args) throws IOException { 77 | CarmichaelNumbers n = new CarmichaelNumbers(); 78 | String currentLine = null; 79 | while ((currentLine = reader.readLine()) != null && 80 | !currentLine.trim().equals("")) { 81 | int v = Integer.parseInt(currentLine.trim()); 82 | if (v == 0) { 83 | break; 84 | } 85 | if (n.isCarmichael(v)) { 86 | System.out.println( 87 | "The number " + v + " is a Carmichael number."); 88 | } else { 89 | System.out.println(v + " is normal."); 90 | } 91 | } 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/Chapter7/EuclidProblem.java: -------------------------------------------------------------------------------- 1 | package com.rvprg.pc; 2 | 3 | import static java.util.Arrays.stream; 4 | import static java.util.stream.Collectors.toList; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | class EuclidProblem { 14 | private static final BufferedReader reader = new BufferedReader( 15 | new InputStreamReader(System.in)); 16 | 17 | public static long[] euclid(long a, long b) { 18 | long s = 0; 19 | long old_s = 1; 20 | long t = 1; 21 | long old_t = 0; 22 | long r = b; 23 | long old_r = a; 24 | while (r != 0) { 25 | long quotient = old_r / r; 26 | long p = r; 27 | r = old_r - quotient * r; 28 | old_r = p; 29 | p = s; 30 | s = old_s - quotient * s; 31 | old_s = p; 32 | p = t; 33 | t = old_t - quotient * t; 34 | old_t = p; 35 | } 36 | return new long[] { old_s, old_t, old_r }; 37 | } 38 | 39 | public static String toString(long[] arr) { 40 | return Arrays.stream(arr).mapToObj(String::valueOf) 41 | .collect(Collectors.joining(" ")); 42 | } 43 | 44 | public static void main(String[] args) throws IOException { 45 | String currentLine = null; 46 | while ((currentLine = reader.readLine()) != null && 47 | !currentLine.trim().equals("")) { 48 | List input = stream(currentLine.trim().split(" ")) 49 | .filter(x -> !x.equals("")).map(Integer::parseInt) 50 | .collect(toList()); 51 | System.out.println(toString(euclid(input.get(0), input.get(1)))); 52 | } 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/Chapter7/Factovisors.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | class Factovisors { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | public static boolean check(int n, int p, int k) { 14 | for (int i = p; i <= n && k > 0; i += p) { 15 | int m = i; 16 | while (m % p == 0) { 17 | m /= p; 18 | k--; 19 | } 20 | } 21 | return k <= 0; 22 | } 23 | 24 | public static boolean solve(int n, int m) { 25 | n = (n == 0) ? 1 : n; 26 | m = (m == 0) ? 1 : m; 27 | if (n >= m) { 28 | return true; 29 | } 30 | int k = 0; 31 | while (m % 2 == 0) { 32 | m /= 2; 33 | k++; 34 | } 35 | if (!check(n, 2, k)) { 36 | return false; 37 | } 38 | for (int i = 3; i <= Math.sqrt(m); i += 2) { 39 | k = 0; 40 | while (m % i == 0) { 41 | m /= i; 42 | k++; 43 | } 44 | if (!check(n, i, k)) { 45 | return false; 46 | } 47 | } 48 | return m <= n; 49 | } 50 | 51 | public static void main(String[] args) throws IOException { 52 | String currentLine = null; 53 | while ((currentLine = reader.readLine()) != null && 54 | !currentLine.trim().equals("")) { 55 | List input = stream(currentLine.trim().split(" ")) 56 | .filter(x -> !x.equals("")).map(Integer::parseInt) 57 | .collect(toList()); 58 | boolean solution = solve(input.get(0), input.get(1)); 59 | System.out.println(input.get(1) + 60 | (solution ? " divides " : " does not divide ") + 61 | input.get(0) + "!"); 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/Chapter7/LightMoreLight.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.BitSet; 6 | import java.util.List; 7 | 8 | class LightMoreLight { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | private final List primes; 12 | private final static int MAX_PRIMES = 70000; 13 | 14 | LightMoreLight() { 15 | BitSet bits = new BitSet(MAX_PRIMES); 16 | for (int i = 2; i < Math.sqrt(MAX_PRIMES); ++i) { 17 | if (!bits.get(i)) { 18 | int k = 0; 19 | int ii = i * i; 20 | int j = ii + k * i; 21 | while (j < MAX_PRIMES) { 22 | bits.set(j); 23 | k++; 24 | j = ii + k * i; 25 | } 26 | } 27 | } 28 | primes = new ArrayList(); 29 | for (int i = 2; i < bits.length(); ++i) { 30 | if (!bits.get(i)) { 31 | primes.add((long) i); 32 | } 33 | } 34 | } 35 | 36 | public long calculate(long value) { 37 | List factors = new ArrayList(); 38 | for (int i = 0; i < primes.size() && value > 1 && 39 | (primes.get(i) * primes.get(i)) <= value; ++i) { 40 | long p = 0; 41 | while (value % primes.get(i) == 0) { 42 | value /= primes.get(i); 43 | p++; 44 | } 45 | if (p > 0) { 46 | factors.add(p); 47 | } 48 | } 49 | if (value > 1) { 50 | factors.add(1L); 51 | } 52 | return factors.stream().map(x -> x + 1).reduce(1L, (a, b) -> a * b); 53 | } 54 | 55 | public static void main(String[] args) throws IOException { 56 | LightMoreLight l = new LightMoreLight(); 57 | String currentLine; 58 | while ((currentLine = reader.readLine()) != null && 59 | !currentLine.trim().equals("0")) { 60 | long value = Long.parseLong(currentLine.trim()); 61 | System.out.println(l.calculate(value) % 2 == 0 ? "no" : "yes"); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Chapter7/Marbles.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | class Marbles { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | public static long[] euclid(long a, long b) { 14 | long s = 0; 15 | long old_s = 1; 16 | long t = 1; 17 | long old_t = 0; 18 | long r = b; 19 | long old_r = a; 20 | while (r != 0) { 21 | long quotient = old_r / r; 22 | long p = r; 23 | r = old_r - quotient * r; 24 | old_r = p; 25 | p = s; 26 | s = old_s - quotient * s; 27 | old_s = p; 28 | p = t; 29 | t = old_t - quotient * t; 30 | old_t = p; 31 | } 32 | return new long[] { old_s, old_t, old_r }; 33 | } 34 | 35 | public static long[] diophant(long a, long b, long c) { 36 | long[] bezouts = euclid(a, b); 37 | if (c % bezouts[2] != 0) { 38 | return null; 39 | } 40 | long e = c / bezouts[2]; 41 | return new long[] { e * bezouts[0], b / bezouts[2], e * bezouts[1], 42 | -a / bezouts[2] }; 43 | } 44 | 45 | public static long[] min(long c1, long c2, long[] solution, long start, 46 | long end) { 47 | long[] min = new long[] { Long.MAX_VALUE, 0, 0 }; 48 | for (long i = start; i <= end; ++i) { 49 | long x = solution[0] + i * solution[1]; 50 | long y = solution[2] + i * solution[3]; 51 | if (x < 0 || y < 0) { 52 | continue; 53 | } 54 | long cost = c1 * x + c2 * y; 55 | if (cost < min[0]) { 56 | min[0] = cost; 57 | min[1] = x; 58 | min[2] = y; 59 | } 60 | } 61 | return min; 62 | } 63 | 64 | public static long[] solve(long c1, long n1, long c2, long n2, long n) { 65 | long[] solution = diophant(n1, n2, n); 66 | if (solution == null) { 67 | return null; 68 | } 69 | long left = -(solution[0] / solution[1]); 70 | long right = (solution[2] / -solution[3]); 71 | long[] minLeft = min(c1, c2, solution, left, left + 1); 72 | long[] minRight = min(c1, c2, solution, right - 1, right); 73 | long[] min = minLeft[0] < minRight[0] ? minLeft : minRight; 74 | return min[0] < Long.MAX_VALUE ? min : null; 75 | } 76 | 77 | public static List parse(String line) { 78 | return stream(line.trim().split(" ")) 79 | .filter(x -> !x.equals("")) 80 | .map(Long::parseLong) 81 | .collect(toList()); 82 | } 83 | 84 | public static void main(String[] args) throws IOException { 85 | String currentLine = null; 86 | while ((currentLine = reader.readLine()) != null) { 87 | long c = Long.parseLong(currentLine); 88 | if (c == 0) { 89 | break; 90 | } 91 | List cn1 = parse(reader.readLine()); 92 | List cn2 = parse(reader.readLine()); 93 | long[] solution = solve(cn1.get(0), cn1.get(1), cn2.get(0), 94 | cn2.get(1), c); 95 | System.out 96 | .println(solution == null ? "failed" 97 | : solution[1] + " " + solution[2]); 98 | } 99 | 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/Chapter7/SmithNumbers.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | class SmithNumbers { 8 | private static final BufferedReader reader = new BufferedReader( 9 | new InputStreamReader(System.in)); 10 | 11 | private static int digitsSum(int value) { 12 | int sum = 0; 13 | while (value > 9) { 14 | sum += (value % 10); 15 | value /= 10; 16 | } 17 | return sum + value; 18 | } 19 | 20 | public static List factor(int m) { 21 | List factors = new ArrayList<>(); 22 | if (m <= 2) { 23 | factors.add(m); 24 | return factors; 25 | } 26 | while (m % 2 == 0) { 27 | m /= 2; 28 | factors.add(2); 29 | } 30 | for (int i = 3; i <= Math.sqrt(m); i += 2) { 31 | while (m % i == 0) { 32 | m /= i; 33 | factors.add(i); 34 | } 35 | } 36 | if (m > 1) { 37 | factors.add(m); 38 | } 39 | return factors; 40 | } 41 | 42 | public static int find(int m) { 43 | int i = m + 1; 44 | while (true) { 45 | List factors = factor(i); 46 | if (factors.size() > 1) { 47 | if (factors.stream().map(SmithNumbers::digitsSum).reduce(Integer::sum) 48 | .get() == digitsSum(i)) { 49 | return i; 50 | } 51 | } 52 | ++i; 53 | } 54 | } 55 | 56 | public static void main(String[] args) throws IOException { 57 | int n = Integer.parseInt(reader.readLine().trim()); 58 | for (int i = 0; i < n; ++i) { 59 | int v = Integer.parseInt(reader.readLine().trim()); 60 | System.out.println(find(v)); 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/Chapter7/SummationOfFourPrimes.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.BitSet; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | class SummationOfFourPrimes { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | private final List primes; 15 | private final static int MAX_PRIMES = 10_000_000; 16 | 17 | SummationOfFourPrimes() { 18 | BitSet bits = new BitSet(MAX_PRIMES); 19 | for (int i = 2; i < Math.sqrt(MAX_PRIMES); ++i) { 20 | if (!bits.get(i)) { 21 | int k = 0; 22 | int ii = i * i; 23 | int j = ii + k * i; 24 | while (j < MAX_PRIMES) { 25 | bits.set(j); 26 | k++; 27 | j = ii + k * i; 28 | } 29 | } 30 | } 31 | primes = new ArrayList<>(); 32 | for (int i = 2; i < bits.length(); ++i) { 33 | if (!bits.get(i)) { 34 | primes.add(i); 35 | } 36 | } 37 | } 38 | 39 | public int[] find(int a, int c, int[] current) { 40 | if (a == 0 && c == -1) { 41 | return current; 42 | } else if (a < 0 || c == -1) { 43 | return null; 44 | } 45 | int startIndex = Collections.binarySearch(primes, a); 46 | startIndex = (startIndex < 0) ? Math.abs(startIndex + 1) : startIndex; 47 | startIndex = primes.size() - 1 >= startIndex ? startIndex 48 | : primes.size() - 1; 49 | for (int i = startIndex; i >= 0; --i) { 50 | current[c] = primes.get(i); 51 | int[] result = find(a - primes.get(i), c - 1, current); 52 | if (result != null) { 53 | return result; 54 | } 55 | } 56 | return null; 57 | } 58 | 59 | public static String toString(int[] arr) { 60 | return Arrays.stream(arr).mapToObj(String::valueOf) 61 | .collect(Collectors.joining(" ")); 62 | } 63 | 64 | public static void main(String[] args) throws IOException { 65 | SummationOfFourPrimes n = new SummationOfFourPrimes(); 66 | String currentLine = null; 67 | while ((currentLine = reader.readLine()) != null && 68 | !currentLine.trim().equals("")) { 69 | int[] res = n.find(Integer.parseInt(currentLine.trim()), 3, 70 | new int[4]); 71 | System.out.println(res != null ? toString(res) : "Impossible."); 72 | } 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/Chapter8/BiggerSquarePleaseMetaProgram.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.InputStreamReader; 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | public class BiggerSquarePleaseMetaProgram { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | private static final String indend8 = " "; 15 | private static final String indend4 = " "; 16 | 17 | private static void printProgram(Map>> solutions) { 18 | System.out.println("import java.io.BufferedReader;"); 19 | System.out.println("import java.io.InputStreamReader;"); 20 | System.out.println(); 21 | System.out.println("public class BiggerSquarePlease {"); 22 | System.out.println(" private static final BufferedReader reader = new BufferedReader("); 23 | System.out.println(" new InputStreamReader(System.in));"); 24 | System.out.println(); 25 | System.out.println(" private static final int[][][] table = new int[][][] {"); 26 | 27 | for (int i = 0; i <= 50; ++i) { 28 | List> solution = solutions.get(i); 29 | if (solution == null || solution.size() == 0) { 30 | System.out.println(indend8 + "{{}}, //" + i); 31 | continue; 32 | } 33 | System.out.print(indend8 + "{"); 34 | for (List s : solution) { 35 | System.out.printf("{%d, %d, %d},", s.get(0), s.get(1), s.get(2)); 36 | } 37 | System.out.println("}, //" + i); 38 | } 39 | System.out.println(indend4 + "};"); 40 | System.out.println(); 41 | System.out.println(indend4 + "public static void main(String[] args) throws Exception {"); 42 | System.out.println(indend4 + " int n = Integer.parseInt(reader.readLine().trim());"); 43 | System.out.println(indend4 + " for (int i = 0; i < n; ++i) {"); 44 | System.out.println(indend4 + " int m = Integer.parseInt(reader.readLine().trim());"); 45 | System.out.println(indend4 + " int[][] solution = table[m];"); 46 | System.out.println(indend4 + " System.out.println(solution.length);"); 47 | System.out.println(indend4 + " for (int[] s : solution) {"); 48 | System.out.println(indend4 + " System.out.println(s[0] + \" \" + s[1] + \" \" + s[2]);"); 49 | System.out.println(indend4 + " }"); 50 | System.out.println(indend4 + " }"); 51 | System.out.println(indend4 + "}"); 52 | System.out.println("}"); 53 | System.out.println(); 54 | } 55 | 56 | public static void main(String[] args) throws Exception { 57 | String currentLine; 58 | Map>> solutions = new HashMap<>(); 59 | while ((currentLine = reader.readLine()) != null) { 60 | int n = Integer.parseInt(currentLine.trim()); 61 | int s = Integer.parseInt(reader.readLine().trim()); 62 | List> solution = new ArrayList<>(); 63 | for (int i = 0; i < s; ++i) { 64 | solution.add(stream(reader.readLine().trim().split(" ")) 65 | .filter(x -> !x.equals("")) 66 | .map(Integer::parseInt) 67 | .collect(toList())); 68 | } 69 | solutions.put(n, solution); 70 | } 71 | printProgram(solutions); 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/Chapter8/GardenOfEden.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.InputStreamReader; 6 | import java.util.List; 7 | 8 | public class GardenOfEden { 9 | private static final BufferedReader reader = new BufferedReader( 10 | new InputStreamReader(System.in)); 11 | 12 | static final boolean[][] trans = new boolean[][] { 13 | { false, false, false }, 14 | { false, false, true }, 15 | { false, true, false }, 16 | { false, true, true }, 17 | { true, false, false }, 18 | { true, false, true }, 19 | { true, true, false }, 20 | { true, true, true } 21 | }; 22 | 23 | final boolean[] auto; 24 | final boolean[] curr; 25 | final boolean[] prev; 26 | boolean reachable; 27 | 28 | GardenOfEden(boolean[] auto, boolean[] curr) { 29 | this.auto = auto; 30 | this.curr = curr; 31 | this.prev = new boolean[curr.length]; 32 | for (int j = 0; j < auto.length; ++j) { 33 | if (auto[j] == curr[0]) { 34 | prev[prev.length - 1] = trans[j][0]; 35 | prev[0] = trans[j][1]; 36 | prev[1] = trans[j][2]; 37 | reachable = backtrack(1); 38 | if (reachable) { 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | 45 | boolean backtrack(int pos) { 46 | for (int j = 0; j < auto.length; ++j) { 47 | if (auto[j] != curr[pos]) { 48 | continue; 49 | } 50 | if (prev[pos - 1] == trans[j][0] && 51 | prev[pos] == trans[j][1]) { 52 | if (pos == curr.length - 1) { 53 | if (prev[0] == trans[j][2]) { 54 | return true; 55 | } 56 | } else if (pos + 1 == curr.length - 1) { 57 | if (prev[pos + 1] == trans[j][2]) { 58 | if (backtrack(pos + 1)) { 59 | return true; 60 | } 61 | } 62 | } else { 63 | prev[pos + 1] = trans[j][2]; 64 | if (backtrack(pos + 1)) { 65 | return true; 66 | } 67 | } 68 | } 69 | } 70 | return false; 71 | } 72 | 73 | public static void main(String[] args) throws Exception { 74 | String currentLine; 75 | while ((currentLine = reader.readLine()) != null && 76 | !currentLine.trim().isEmpty()) { 77 | List input = stream(currentLine.trim().split(" ")) 78 | .filter(x -> !x.equals("")) 79 | .collect(toList()); 80 | boolean[] automaton = new boolean[8]; 81 | String id = Integer.toBinaryString(Integer.parseInt(input.get(0))); 82 | for (int i = id.length() - 1, j = 0; i >= 0; --i, ++j) { 83 | automaton[j] = id.charAt(i) == '1'; 84 | } 85 | boolean[] state = new boolean[input.get(2).length()]; 86 | for (int i = 0; i < state.length; ++i) { 87 | state[i] = input.get(2).charAt(i) == '1'; 88 | } 89 | System.out 90 | .println(new GardenOfEden(automaton, state).reachable ? "REACHABLE" 91 | : "GARDEN OF EDEN"); 92 | } 93 | } 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/Chapter8/LittleBishops.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | 10 | class LittleBishops { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | private final int[][] attack; 15 | private final int n; 16 | private final int totalCount; 17 | 18 | public LittleBishops(int n, int k) { 19 | this.attack = new int[n][n]; 20 | this.n = n; 21 | if (k > 0) { 22 | int total = 0; 23 | for (int i = 1; i < k; ++i) { 24 | int v = getCount(0, i); 25 | if (v > 0) { 26 | total += v * getCount(1, k - i); 27 | } 28 | } 29 | this.totalCount = total + getCount(0, k) + getCount(1, k); 30 | } else { 31 | this.totalCount = 1; 32 | } 33 | } 34 | 35 | private int getCount(int s, int k) { 36 | AtomicInteger counter = new AtomicInteger(0); 37 | count(s, k, counter); 38 | return counter.get(); 39 | } 40 | 41 | private void attack(int i, int j, int d) { 42 | while (i + 1 < n && j + 1 < n) { 43 | attack[++i][++j] += d; 44 | } 45 | } 46 | 47 | public void count(int s, int k, AtomicInteger counter) { 48 | if (k == 0) { 49 | counter.incrementAndGet(); 50 | return; 51 | } 52 | 53 | for (int i = s; i <= 2 * n - 1; i += 2) { 54 | int ii = i >= n ? n * (i - n + 2) - 1 : i; 55 | int squares = i >= n ? 2 * n - i - 1 : i + 1; 56 | for (int j = ii, num = 0; num < squares; j += (n - 1), ++num) { 57 | int x = j / n; 58 | int y = j % n; 59 | if (attack[x][y] > 0) { 60 | continue; 61 | } 62 | attack(x, y, 1); 63 | count(i + 2, k - 1, counter); 64 | attack(x, y, -1); 65 | } 66 | } 67 | } 68 | 69 | public static void main(String[] args) throws IOException { 70 | int[][] memo = new int[9][65]; 71 | for (int i = 0; i < 9; ++i) { 72 | for (int j = 0; j < 65; ++j) { 73 | memo[i][j] = -1; 74 | } 75 | } 76 | 77 | String currentLine = null; 78 | while ((currentLine = reader.readLine()) != null) { 79 | List input = stream(currentLine.trim().split(" ")) 80 | .filter(x -> !x.equals("")).map(Integer::parseInt) 81 | .collect(toList()); 82 | if (input.get(0) == 0 && input.get(1) == 0) { 83 | break; 84 | } 85 | int i = input.get(0); 86 | int j = input.get(1); 87 | if (memo[i][j] == -1) { 88 | LittleBishops s = new LittleBishops(i, j); 89 | memo[i][j] = s.totalCount; 90 | } 91 | System.out.println(memo[i][j]); 92 | } 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/Chapter8/Queue.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | import java.util.stream.LongStream; 9 | 10 | public class Queue { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | private final int n; 15 | private final int k; 16 | private final int[] buckets; 17 | private final int[] queue; 18 | private final int[] values; 19 | private final boolean[] skip; 20 | private long total; 21 | private long counter; 22 | 23 | private static final long[] factorial = LongStream.rangeClosed(0, 13) 24 | .map(f -> f == 0 ? 1 25 | : LongStream.rangeClosed(1, f).reduce(1L, 26 | (x, y) -> x * y)) 27 | .toArray(); 28 | 29 | private static final Long[][][] cache = new Long[13 + 1][13 + 1][13 + 1]; 30 | 31 | public Queue(int n, int l, int r) { 32 | this.n = n; 33 | this.k = l - 1; 34 | buckets = new int[n + 1]; 35 | skip = new boolean[n + 1]; 36 | queue = new int[l + r - 2]; 37 | values = new int[n - (l + r - 2) - 1 < 0 ? 0 : n - (l + r - 2) - 1]; 38 | skip[n] = true; 39 | if (cache[n][l][r] != null) { 40 | total = cache[n][l][r]; 41 | } else { 42 | select(0); 43 | cache[n][l][r] = total; 44 | } 45 | } 46 | 47 | private void select(int pos) { 48 | if (pos == queue.length) { 49 | for (int i = 1, j = 0; i <= n; ++i) { 50 | if (!skip[i]) { 51 | values[j++] = i; 52 | } 53 | } 54 | counter = 0; 55 | count(0); 56 | int nn = queue.length; 57 | total += counter * factorial[nn] / 58 | (factorial[k] * factorial[nn - k]); 59 | return; 60 | } 61 | 62 | int start = pos - 1 >= 0 ? queue[pos - 1] + 1 : 1; 63 | for (int i = start; i < n; ++i) { 64 | queue[pos] = i; 65 | skip[i] = true; 66 | select(pos + 1); 67 | skip[i] = false; 68 | } 69 | } 70 | 71 | private void count(int pos) { 72 | if (pos == values.length) { 73 | long permutations = 1; 74 | for (int i = 0; i < buckets.length; ++i) { 75 | permutations *= factorial[buckets[i]]; 76 | } 77 | counter += permutations; 78 | return; 79 | } 80 | 81 | for (int bucket : queue) { 82 | if (bucket > values[pos]) { 83 | buckets[bucket]++; 84 | count(pos + 1); 85 | buckets[bucket]--; 86 | } 87 | } 88 | } 89 | 90 | public static void main(String[] args) throws IOException { 91 | int n = Integer.parseInt(reader.readLine().trim()); 92 | for (int i = 0; i < n; ++i) { 93 | List line = stream(reader.readLine().split(" ")) 94 | .filter(x -> !x.equals("")) 95 | .map(Integer::parseInt) 96 | .collect(toList()); 97 | int l = line.get(1); 98 | int r = line.get(2); 99 | if (l + r - 1 > 13) { 100 | System.out.println(0); 101 | } else { 102 | Queue q = new Queue(line.get(0), l, r); 103 | System.out.println(q.total); 104 | } 105 | } 106 | } 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/Chapter8/ServicingStations.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.InputStreamReader; 6 | import java.util.ArrayDeque; 7 | import java.util.ArrayList; 8 | import java.util.Deque; 9 | import java.util.List; 10 | 11 | public class ServicingStations { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | 15 | static class Bits { 16 | long v = 0L; 17 | 18 | boolean get(int b) { 19 | return (this.v & (1L << b)) != 0; 20 | } 21 | 22 | void set(int b) { 23 | this.v |= (1L << b); 24 | } 25 | } 26 | 27 | private final Bits[] cities; 28 | private final Bits[] stack; 29 | private int count; 30 | private Bits currentGraph; 31 | 32 | 33 | public ServicingStations(Bits[] cities) throws Exception { 34 | count = 0; 35 | this.stack = new Bits[40]; 36 | for (int i = 0; i < this.stack.length; ++i) { 37 | this.stack[i] = new Bits(); 38 | } 39 | this.cities = cities; 40 | for (Bits graph : graphs(this.cities)) { 41 | currentGraph = graph; 42 | for (int i = 0; i < cities.length; ++i) { 43 | if (backtrack(i, 0, 0)) { 44 | count += i; 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | 51 | private List graphs(Bits[] cities) { 52 | List graphs = new ArrayList<>(); 53 | Bits all = new Bits(); 54 | boolean finished = false; 55 | while (!finished) { 56 | finished = true; 57 | for (int i = 0; i < cities.length; ++i) { 58 | if (!all.get(i)) { 59 | finished = false; 60 | Bits graph = bfs(i, cities); 61 | graphs.add(graph); 62 | all.v |= graph.v; 63 | break; 64 | } 65 | } 66 | } 67 | return graphs; 68 | } 69 | 70 | private Bits bfs(int s, Bits[] cities) { 71 | Deque next = new ArrayDeque<>(); 72 | Bits visited = new Bits(); 73 | next.add(s); 74 | while (!next.isEmpty()) { 75 | int n = next.pop(); 76 | for (int i = 0; i < cities.length; ++i) { 77 | if (cities[n].get(i) && !visited.get(i)) { 78 | next.add(i); 79 | } 80 | } 81 | visited.set(n); 82 | } 83 | return visited; 84 | } 85 | 86 | private boolean backtrack(int count, int pos, int depth) throws Exception { 87 | if (count == 0) { 88 | return ((stack[depth].v & 89 | currentGraph.v) == currentGraph.v); 90 | } 91 | for (int i = pos; i < cities.length; ++i) { 92 | if (!currentGraph.get(i) && !stack[depth].get(i)) { 93 | continue; 94 | } 95 | 96 | stack[depth + 1].v = stack[depth].v | cities[i].v; 97 | if (stack[depth + 1].v == stack[depth].v) { 98 | continue; 99 | } 100 | 101 | if (backtrack(count - 1, i + 1, depth + 1)) { 102 | return true; 103 | } 104 | } 105 | return false; 106 | } 107 | 108 | 109 | private static List parseLine(String line) { 110 | return stream(line.split(" ")) 111 | .filter(x -> !x.equals("")) 112 | .map(Integer::parseInt) 113 | .collect(toList()); 114 | } 115 | 116 | public static void main(String[] args) throws Exception { 117 | String currentLine; 118 | while ((currentLine = reader.readLine()) != null) { 119 | if (currentLine.trim().isEmpty()) { 120 | continue; 121 | } 122 | List nm = parseLine(currentLine); 123 | int n = nm.get(0); 124 | int m = nm.get(1); 125 | if (n == 0 && m == 0) { 126 | break; 127 | } 128 | Bits[] cities = new Bits[n]; 129 | for (int i = 0; i < cities.length; ++i) { 130 | cities[i] = new Bits(); 131 | cities[i].set(i); 132 | } 133 | while (m > 0) { 134 | if ((currentLine = reader.readLine()).trim().isEmpty()) { 135 | continue; 136 | } 137 | List fromTo = parseLine(currentLine.trim()); 138 | cities[fromTo.get(0) - 1].set(fromTo.get(1) - 1); 139 | cities[fromTo.get(1) - 1].set(fromTo.get(0) - 1); 140 | m--; 141 | } 142 | System.out.println(new ServicingStations(cities).count); 143 | } 144 | } 145 | 146 | } 147 | 148 | -------------------------------------------------------------------------------- /src/Chapter8/TugOfWar.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.Arrays; 4 | 5 | public class TugOfWar { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | 9 | private static int[] solve(int[] arr) { 10 | int n = arr.length; 11 | int sum = Arrays.stream(arr).sum(); 12 | long[] m = new long[sum + 1]; 13 | m[0] = 1; 14 | for (int i = 0; i < n; ++i) { 15 | for (int j = sum - arr[i]; j >= 0; --j) { 16 | m[j + arr[i]] |= m[j] << 1L; 17 | } 18 | } 19 | 20 | for (int i = sum / 2; i >= 0; --i) { 21 | if (n % 2 == 0) { 22 | if ((m[i] & 1L << (n / 2)) > 0) { 23 | return new int[] { i, sum - i }; 24 | } 25 | } else { 26 | if ((m[i] & 1L << (n / 2)) > 0 || 27 | (m[i] & 1L << (n / 2 + 1)) > 0) { 28 | return new int[] { i, sum - i }; 29 | } 30 | } 31 | } 32 | 33 | return null; 34 | } 35 | 36 | public static void main(String[] args) throws Exception { 37 | int n = Integer.parseInt(reader.readLine().trim()); 38 | reader.readLine(); 39 | for (int i = 0; i < n; ++i) { 40 | int m = Integer.parseInt(reader.readLine().trim()); 41 | int[] arr = new int[m]; 42 | for (int j = 0; j < m; ++j) { 43 | arr[j] = Integer.parseInt(reader.readLine().trim()); 44 | } 45 | int[] s = solve(arr); 46 | System.out.println(s[0] + " " + s[1]); 47 | if (i < n - 1) { 48 | System.out.println(); 49 | reader.readLine(); 50 | } 51 | } 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/Chapter9/Bicoloring.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayDeque; 8 | import java.util.Deque; 9 | import java.util.HashMap; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | public class Bicoloring { 16 | private static final BufferedReader reader = new BufferedReader( 17 | new InputStreamReader(System.in)); 18 | 19 | private static void add(Map> graph, Integer nodeFrom, 20 | Integer nodeTo) { 21 | if (!graph.containsKey(nodeFrom)) { 22 | graph.put(nodeFrom, new HashSet()); 23 | } 24 | if (!graph.containsKey(nodeTo)) { 25 | graph.put(nodeTo, new HashSet()); 26 | } 27 | graph.get(nodeFrom).add(nodeTo); 28 | graph.get(nodeTo).add(nodeFrom); 29 | } 30 | 31 | private static boolean solve( 32 | Map> graph) { 33 | if (graph.size() == 0) { 34 | return true; 35 | } 36 | 37 | Deque next = new ArrayDeque<>(); 38 | Set visited = new HashSet<>(); 39 | Map colors = new HashMap<>(); 40 | 41 | boolean color = true; 42 | Integer start = graph.keySet().iterator().next(); 43 | next.push(start); 44 | colors.put(start, color); 45 | 46 | while (!next.isEmpty()) { 47 | Integer node = next.pop(); 48 | color = colors.get(node); 49 | for (Integer adjNode : graph.get(node)) { 50 | if (!visited.contains(adjNode)) { 51 | visited.add(adjNode); 52 | next.addLast(adjNode); 53 | colors.put(adjNode, !color); 54 | } else if (colors.get(adjNode) == color) { 55 | return false; 56 | } 57 | } 58 | } 59 | 60 | return true; 61 | } 62 | 63 | public static void main(String[] args) throws IOException { 64 | while (true) { 65 | int n = Integer.parseInt(reader.readLine().trim()); 66 | if (n == 0) { 67 | break; 68 | } 69 | n = Integer.parseInt(reader.readLine().trim()); 70 | Map> graph = new HashMap<>(); 71 | for (int j = 0; j < n; ++j) { 72 | List toFrom = stream( 73 | reader.readLine().trim().split(" ")) 74 | .filter(x -> !x.equals("")) 75 | .map(Integer::parseInt) 76 | .collect(toList()); 77 | add(graph, toFrom.get(0), toFrom.get(1)); 78 | } 79 | System.out 80 | .println( 81 | solve(graph) ? "BICOLORABLE." : "NOT BICOLORABLE."); 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/Chapter9/EditStepLadders.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class EditStepLadders { 12 | private static final BufferedReader reader = new BufferedReader( 13 | new InputStreamReader(System.in)); 14 | 15 | private static void add(List list, Set dict, String word, 16 | String newWord) { 17 | if (newWord.compareTo(word) < 0 && dict.contains(newWord)) { 18 | list.add(newWord); 19 | } 20 | } 21 | 22 | private static List adjacent(Set dict, String word) { 23 | List words = new ArrayList<>(); 24 | char[] wordArr = word.toCharArray(); 25 | for (int i = 0; i <= word.length(); ++i) { 26 | for (char c = 'a'; c <= 'z'; ++c) { 27 | add(words, dict, word, new StringBuilder().append(wordArr, 0, i) 28 | .append(c) 29 | .append(wordArr, i, wordArr.length - i).toString()); 30 | if (i < word.length()) { 31 | add(words, dict, word, 32 | new StringBuilder().append(wordArr, 0, i) 33 | .append(c) 34 | .append(wordArr, i + 1, 35 | wordArr.length - i - 1) 36 | .toString()); 37 | } 38 | } 39 | if (i < word.length()) { 40 | add(words, dict, word, 41 | new StringBuilder().append(wordArr, 0, i) 42 | .append(wordArr, i + 1, wordArr.length - i - 1) 43 | .toString()); 44 | } 45 | } 46 | return words; 47 | } 48 | 49 | private static int solve(Set dict) { 50 | List sorted = new ArrayList<>(dict); 51 | sorted.sort((x, y) -> x.compareTo(y)); 52 | Map lengths = new HashMap<>(); 53 | Integer answer = 1; 54 | for (String word : sorted) { 55 | Integer max = 1; 56 | for (String source : adjacent(dict, word)) { 57 | Integer length = lengths.get(source); 58 | max = Math.max(max, length != null ? length + 1 : -1); 59 | } 60 | lengths.put(word, max); 61 | answer = Math.max(max, answer); 62 | } 63 | return answer; 64 | } 65 | 66 | public static void main(String[] args) throws IOException { 67 | Set dict = new HashSet<>(); 68 | String currentLine; 69 | while ((currentLine = reader.readLine()) != null && 70 | !currentLine.trim().isEmpty()) { 71 | dict.add(currentLine.trim()); 72 | } 73 | System.out.println(solve(dict)); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/Chapter9/HanoiTowerTroublesAgain.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class HanoiTowerTroublesAgain { 6 | private static final BufferedReader reader = new BufferedReader( 7 | new InputStreamReader(System.in)); 8 | 9 | public static boolean isSquare(int v) { 10 | int i = (int) Math.sqrt(v); 11 | return i * i == v; 12 | } 13 | 14 | public static int solve(int m) { 15 | int j = 0; 16 | int i = 0; 17 | int[] v = new int[m]; 18 | while (i < m) { 19 | j++; 20 | for (i = 0; i < m; ++i) { 21 | if (v[i] == 0 || isSquare(v[i] + j)) { 22 | v[i] = j; 23 | break; 24 | } 25 | } 26 | } 27 | return j - 1; 28 | } 29 | 30 | public static void main(String[] args) throws IOException { 31 | int n = Integer.parseInt(reader.readLine().trim()); 32 | for (int i = 0; i < n; ++i) { 33 | int m = Integer.parseInt(reader.readLine().trim()); 34 | System.out.println(solve(m)); 35 | } 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/Chapter9/PlayingWithWheels.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayDeque; 8 | import java.util.Arrays; 9 | import java.util.Deque; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | public class PlayingWithWheels { 17 | private static final BufferedReader reader = new BufferedReader( 18 | new InputStreamReader(System.in)); 19 | 20 | static class Node { 21 | int[] node; 22 | 23 | @Override 24 | public int hashCode() { 25 | final int prime = 31; 26 | int result = 1; 27 | result = prime * result + Arrays.hashCode(node); 28 | return result; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object obj) { 33 | if (this == obj) 34 | return true; 35 | if (obj == null) 36 | return false; 37 | if (getClass() != obj.getClass()) 38 | return false; 39 | Node other = (Node) obj; 40 | if (!Arrays.equals(node, other.node)) 41 | return false; 42 | return true; 43 | } 44 | 45 | public Node(List s) { 46 | this.node = new int[s.size()]; 47 | for (int i = 0; i < s.size(); ++i) { 48 | this.node[i] = s.get(i).intValue(); 49 | } 50 | } 51 | 52 | public Node(Node node, int i, int p) { 53 | this.node = Arrays.copyOf(node.node, node.node.length); 54 | this.node[i] += p; 55 | if (this.node[i] < 0) { 56 | this.node[i] = 9; 57 | } else { 58 | this.node[i] %= 10; 59 | } 60 | } 61 | } 62 | 63 | private static Set adjacent(Node node) { 64 | Set adjacent = new HashSet<>(); 65 | for (int i = 0; i < node.node.length; ++i) { 66 | adjacent.add(new Node(node, i, 1)); 67 | adjacent.add(new Node(node, i, -1)); 68 | } 69 | return adjacent; 70 | } 71 | 72 | private static int solve(Node start, Node end, Set forbidden) { 73 | if (start.equals(end)) { 74 | return 0; 75 | } 76 | 77 | Deque next = new ArrayDeque<>(); 78 | Set visited = new HashSet<>(); 79 | Map depths = new HashMap<>(); 80 | 81 | int depth = 0; 82 | next.push(start); 83 | depths.put(start, depth); 84 | 85 | while (!next.isEmpty()) { 86 | Node node = next.pop(); 87 | depth = depths.get(node); 88 | for (Node adjNode : adjacent(node)) { 89 | if (adjNode.equals(end)) { 90 | return forbidden.contains(end) ? -1 : depth + 1; 91 | } 92 | if (!forbidden.contains(adjNode) && 93 | !visited.contains(adjNode)) { 94 | visited.add(adjNode); 95 | next.addLast(adjNode); 96 | depths.put(adjNode, depth + 1); 97 | } 98 | } 99 | } 100 | 101 | return -1; 102 | } 103 | 104 | private static List parseLine(String line) { 105 | return stream(line.trim().split(" ")) 106 | .filter(x -> !x.equals("")) 107 | .map(Integer::parseInt) 108 | .collect(toList()); 109 | } 110 | 111 | public static void main(String[] args) throws IOException { 112 | int n = Integer.parseInt(reader.readLine().trim()); 113 | for (int i = 0; i < n; ++i) { 114 | String currentLine = ""; 115 | while ((currentLine = reader.readLine()).trim().equals("")) 116 | ; 117 | Node start = new Node(parseLine(currentLine)); 118 | Node end = new Node(parseLine(reader.readLine())); 119 | int m = Integer.parseInt(reader.readLine().trim()); 120 | Set forbidden = new HashSet<>(); 121 | for (int j = 0; j < m; ++j) { 122 | forbidden.add(new Node(parseLine(reader.readLine()))); 123 | } 124 | System.out.println(solve(start, end, forbidden)); 125 | } 126 | } 127 | } 128 | 129 | -------------------------------------------------------------------------------- /src/Chapter9/SlashMaze.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayDeque; 8 | import java.util.ArrayList; 9 | import java.util.Deque; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | public class SlashMaze { 17 | private static final BufferedReader reader = new BufferedReader( 18 | new InputStreamReader(System.in)); 19 | 20 | private static int[] find(Map> graph) { 21 | int count = 0; 22 | int max = 0; 23 | Set visited = new HashSet<>(); 24 | while (true) { 25 | int[] m = new int[] { 0, 0 }; 26 | Integer src = graph.keySet().stream() 27 | .filter(x -> !visited.contains(x)) 28 | .findFirst().orElse(Integer.MIN_VALUE); 29 | if (src == Integer.MIN_VALUE) { 30 | break; 31 | } 32 | find(graph, visited, src, m); 33 | count += m[0]; 34 | max = Math.max(max, m[1]); 35 | } 36 | return new int[] { count, max / 2 }; 37 | } 38 | 39 | private static void find(Map> graph, 40 | Set visited, int parent, int m[]) { 41 | Deque stack = new ArrayDeque<>(); 42 | Map depths = new HashMap<>(); 43 | int src = parent; 44 | stack.push(src); 45 | depths.put(src, 0); 46 | 47 | while (!stack.isEmpty()) { 48 | src = stack.pop(); 49 | int depth = depths.get(src); 50 | if (!visited.contains(src)) { 51 | visited.add(src); 52 | for (int adj : graph.get(src)) { 53 | if (adj == parent && depth > 2) { 54 | m[0] += 1; 55 | m[1] = Math.max(m[1], depth + 1); 56 | } 57 | stack.push(adj); 58 | depths.put(adj, depth + 1); 59 | } 60 | } 61 | } 62 | } 63 | 64 | private static List parseLine(String line) { 65 | return stream(line.trim().split(" ")) 66 | .filter(x -> !x.equals("")) 67 | .map(Integer::parseInt) 68 | .collect(toList()); 69 | } 70 | 71 | public static void add(Map> graph, int src, 72 | int dst) { 73 | if (!graph.containsKey(src)) { 74 | graph.put(src, new ArrayList<>()); 75 | } 76 | if (!graph.containsKey(dst)) { 77 | graph.put(dst, new ArrayList<>()); 78 | } 79 | graph.get(src).add(dst); 80 | graph.get(dst).add(src); 81 | } 82 | 83 | public static void main(String[] args) throws IOException { 84 | String currentLine; 85 | int scenario = 1; 86 | while ((currentLine = reader.readLine()) != null && 87 | !currentLine.trim().isEmpty()) { 88 | List wh = parseLine(currentLine); 89 | if (wh.get(0) == 0 && wh.get(1) == 0) { 90 | break; 91 | } 92 | int node = 0; 93 | Map> graph = new HashMap<>(); 94 | for (int i = 0; i < wh.get(1); ++i) { 95 | currentLine = reader.readLine().trim(); 96 | for (char c : currentLine.toCharArray()) { 97 | if (c == '/') { 98 | add(graph, node, node + 1); 99 | add(graph, node + 2, node + 3); 100 | } else if (c == '\\') { 101 | add(graph, node, node + 3); 102 | add(graph, node + 1, node + 2); 103 | } 104 | add(graph, node, node - 2); 105 | int nodeBelow = node + (wh.get(0) * 4) + 1; 106 | add(graph, node + 3, nodeBelow); 107 | node += 4; 108 | } 109 | } 110 | int[] result = find(graph); 111 | System.out.println("Maze #" + scenario + ":"); 112 | if (result[0] > 0) { 113 | System.out.println( 114 | result[0] + " Cycles; the longest has length " + 115 | result[1] + "."); 116 | } else { 117 | System.out.println("There are no cycles."); 118 | } 119 | scenario++; 120 | System.out.println(); 121 | } 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/Chapter9/TheTouristGuide.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | public class TheTouristGuide { 10 | private static final BufferedReader reader = new BufferedReader( 11 | new InputStreamReader(System.in)); 12 | 13 | private static int solve(int[][] w, int size, int s, int e, 14 | int t) { 15 | int[][] d = new int[size][size]; 16 | for (int i = 0; i < size; i++) { 17 | for (int j = 0; j < size; j++) { 18 | d[i][j] = w[i][j]; 19 | } 20 | } 21 | for (int i = 0; i < size; i++) { 22 | d[i][i] = 0; 23 | } 24 | for (int k = 0; k < size; k++) { 25 | for (int i = 0; i < size; i++) { 26 | for (int j = 0; j < size; j++) { 27 | d[i][j] = Math.max(d[i][j], Math.min(d[i][k], d[k][j])); 28 | } 29 | } 30 | } 31 | return d[s][e]; 32 | } 33 | 34 | private static List parseLine(String line) { 35 | return stream(line.trim().split(" ")) 36 | .filter(x -> !x.equals("")) 37 | .map(Integer::parseInt) 38 | .collect(toList()); 39 | } 40 | 41 | public static void main(String[] args) throws IOException { 42 | String currentLine; 43 | int scenario = 1; 44 | while ((currentLine = reader.readLine()) != null && 45 | !currentLine.trim().isEmpty()) { 46 | List nr = parseLine(currentLine); 47 | if (nr.get(0) == 0 && nr.get(1) == 0) { 48 | break; 49 | } 50 | int size = nr.get(0) + 1; 51 | int[][] w = new int[size][size]; 52 | for (int i = 0; i < nr.get(1); ++i) { 53 | List node = parseLine(reader.readLine()); 54 | w[node.get(0)][node.get(1)] = node.get(2); 55 | w[node.get(1)][node.get(0)] = node.get(2); 56 | } 57 | List sdt = parseLine(reader.readLine()); 58 | int m = solve(w, size, sdt.get(0), sdt.get(1), 59 | sdt.get(2)); 60 | int c = (sdt.get(2)) / (m - 1); 61 | if (sdt.get(2) % (m - 1) != 0) { 62 | c++; 63 | } 64 | System.out.println("Scenario #" + scenario); 65 | System.out.println("Minimum Number of Trips = " + c); 66 | System.out.println(); 67 | scenario++; 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/Chapter9/TowerOfCubes.java: -------------------------------------------------------------------------------- 1 | import static java.util.Arrays.stream; 2 | import static java.util.stream.Collectors.toList; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class TowerOfCubes { 11 | private static final BufferedReader reader = new BufferedReader( 12 | new InputStreamReader(System.in)); 13 | 14 | final static int[] map = new int[] { 1, 0, 3, 2, 5, 4 }; 15 | final static String[] toString = new String[] { "front", "back", 16 | "left", "right", "top", "bottom" }; 17 | final List tower = new ArrayList<>(); 18 | final int[][] table; 19 | final int[][][] refs; 20 | int height = 0; 21 | int colorIdx = 0; 22 | int head = 0; 23 | 24 | TowerOfCubes(List> cubes) { 25 | table = new int[cubes.size()][6]; 26 | refs = new int[cubes.size()][6][2]; 27 | buildUpTable(cubes); 28 | buildUpTower(); 29 | } 30 | 31 | private void buildUpTower() { 32 | int currentColorIdx = colorIdx; 33 | while (true) { 34 | tower.add((head + 1) + " " + toString[currentColorIdx]); 35 | int[] ref = refs[head][currentColorIdx]; 36 | if (ref == null) { 37 | break; 38 | } 39 | head = ref[0]; 40 | currentColorIdx = ref[1]; 41 | } 42 | } 43 | 44 | private static int indexOf(int start, int value, List array) { 45 | for (int i = start; i < array.size(); ++i) { 46 | if (array.get(i) == value) { 47 | return i; 48 | } 49 | } 50 | return -1; 51 | } 52 | 53 | private void buildUpTable(List> cubes) { 54 | for (int current = cubes.size() - 1; current >= 0; --current) { 55 | List cube = cubes.get(current); 56 | for (int j = 0; j < 6; ++j) { 57 | int color = cube.get(map[j]); 58 | int max = 1; 59 | refs[current][j] = null; 60 | for (int i = current + 1; i < cubes.size(); ++i) { 61 | int topColorIndex = -1; 62 | while ((topColorIndex = indexOf(topColorIndex + 1, color, 63 | cubes.get(i))) != -1) { 64 | if (max < table[i][topColorIndex] + 1) { 65 | max = table[i][topColorIndex] + 1; 66 | refs[current][j] = new int[] { i, topColorIndex }; 67 | } 68 | } 69 | } 70 | table[current][j] = max; 71 | if (height < max) { 72 | colorIdx = j; 73 | height = max; 74 | head = current; 75 | } 76 | } 77 | } 78 | } 79 | 80 | public static void main(String[] args) throws IOException { 81 | String currentLine; 82 | int caseNo = 1; 83 | while ((currentLine = reader.readLine()) != null) { 84 | while (currentLine.trim().isEmpty()) { 85 | currentLine = reader.readLine(); 86 | } 87 | int n = Integer.parseInt(currentLine.trim()); 88 | if (n == 0) { 89 | break; 90 | } 91 | List> cubes = new ArrayList<>(); 92 | for (int i = 0; i < n; ++i) { 93 | cubes.add(stream( 94 | reader.readLine().trim().split(" ")) 95 | .filter(x -> !x.equals("")) 96 | .map(Integer::parseInt) 97 | .collect(toList())); 98 | } 99 | System.out.println("Case #" + (caseNo++)); 100 | TowerOfCubes toc = new TowerOfCubes(cubes); 101 | System.out.println(toc.height); 102 | toc.tower.stream().forEach(System.out::println); 103 | System.out.println(); 104 | } 105 | } 106 | } 107 | 108 | --------------------------------------------------------------------------------