/cjava/src/main/java/codejam/y2008/round_3/endless_knight/Main.java

https://github.com/eric7237cire/CodeJam · Java · 195 lines · 113 code · 40 blank · 42 comment · 26 complexity · 6c687d22a51f8987773572b3c766b298 MD5 · raw file

  1. package codejam.y2008.round_3.endless_knight;
  2. import java.util.Collections;
  3. import java.util.Comparator;
  4. import java.util.List;
  5. import java.util.Scanner;
  6. import org.apache.commons.math3.fraction.Fraction;
  7. import codejam.utils.geometry.PointInt;
  8. import codejam.utils.main.InputFilesHandler;
  9. import codejam.utils.main.Runner.TestCaseInputScanner;
  10. import codejam.utils.multithread.Consumer.TestCaseHandler;
  11. import codejam.utils.utils.LargeNumberUtils;
  12. import com.google.common.collect.ComparisonChain;
  13. import com.google.common.collect.Lists;
  14. public class Main extends InputFilesHandler implements TestCaseHandler<InputData>, TestCaseInputScanner<InputData>
  15. {
  16. public Main() {
  17. super("D", 1, 1, 1);
  18. //((ch.qos.logback.classic.Logger) log).setLevel(Level.INFO);
  19. }
  20. @Override
  21. public InputData readInput(Scanner scanner, int testCase)
  22. {
  23. InputData in = new InputData(testCase);
  24. in.H = scanner.nextInt();
  25. in.W = scanner.nextInt();
  26. in.R = scanner.nextInt();
  27. in.rocksOrig = new PointInt[in.R];
  28. for (int i = 0; i < in.R; ++i)
  29. {
  30. int row = scanner.nextInt();
  31. int col = scanner.nextInt();
  32. in.rocksOrig[i] = new PointInt(col, row);
  33. }
  34. return in;
  35. }
  36. /*
  37. * example in solution
  38. *
  39. * 11 height
  40. * 13 width
  41. *
  42. * going by diags
  43. * 1,1 3,2 5,3 7,4 9,5 11,6
  44. * 2,3 4,4 6,5 8,6 10,7 12,8
  45. * 3,5 5,6 7,7 9,8 11,9 13,10
  46. * 4,7 6,8 8,9 10,10 12,11 14,12
  47. *
  48. * these coords will be transformed to
  49. * 0,0 1,0 2,0 3,0 4,0 5,0
  50. * 0,1 1,1 2,1 3,1 4,1 5,1
  51. * 0,2 1,2 2,2 3,2 4,2 5,2
  52. * 0,3 1,3 2,3 3,3 4,3 5,3
  53. */
  54. void convertBasis(InputData in)
  55. {
  56. /*
  57. Fraction[][] basisMatrix = new Fraction[][] {
  58. {2d/3, -1d/3},
  59. {-1d/3, 2d/3}
  60. this is the inverse of
  61. new double[][] {
  62. {2d, 1d},
  63. {1d, 2d},
  64. });
  65. LUDecomposition lu = new LUDecomposition(m);
  66. RealMatrix inv = lu.getSolver().getInverse();
  67. };*/
  68. Fraction a = new Fraction(2, 3);
  69. Fraction b = new Fraction(-1, 3);
  70. in.rocks = Lists.newArrayList();
  71. for (PointInt rock : in.rocksOrig)
  72. {
  73. Fraction x = a.multiply(rock.x()-1).add(b.multiply(rock.y()-1));
  74. Fraction y = b.multiply(rock.x()-1).add(a.multiply(rock.y()-1));
  75. if (x.getDenominator() == 1 && y.getDenominator() == 1)
  76. {
  77. PointInt pt = new PointInt(x.intValue(), y.intValue());
  78. if (pt.x() >= 0 && pt.y() >= 0)
  79. in.rocks.add(pt);
  80. }
  81. }
  82. Fraction x = a.multiply(in.W-1).add(b.multiply(in.H-1));
  83. Fraction y = b.multiply(in.W-1).add(a.multiply(in.H-1));
  84. if (x.getDenominator() == 1 &&
  85. y.getDenominator() == 1 && x.intValue() >= 0 && y.intValue() >= 0)
  86. {
  87. in.finalCorner = new PointInt(x.intValue(),y.intValue());
  88. }
  89. }
  90. private static class RockSorter implements Comparator<PointInt>
  91. {
  92. @Override
  93. public int compare(PointInt o1, PointInt o2)
  94. {
  95. return ComparisonChain.start().compare(o1.x(),o2.x()).compare(o1.y(), o2.y()).result();
  96. }
  97. }
  98. static int[][] preCal = null;
  99. @Override
  100. public String handleCase(InputData in)
  101. {
  102. convertBasis(in);
  103. log.debug("Rocks {}", in.rocks);
  104. log.debug("Final {}", in.finalCorner);
  105. //Final corner not reachable
  106. if (in.finalCorner == null) {
  107. return String.format("Case #%d: 0", in.testCase);
  108. }
  109. final int mod = 10007;
  110. if (preCal == null)
  111. preCal = LargeNumberUtils.generateModedCombin(mod-1, mod);
  112. int subsets = 1 << in.rocks.size();
  113. Collections.sort(in.rocks, new RockSorter());
  114. int totalWays = 0;
  115. for(int perm = 0; perm < subsets; ++perm)
  116. {
  117. /**
  118. * Calculate ways to go from start hitting all the rocks in subset
  119. * to the end
  120. */
  121. List<PointInt> subSet = Lists.newArrayList();
  122. subSet.add(new PointInt(0,0));
  123. //Build up the subset list
  124. for(int r = 0; r < in.rocks.size(); ++r) {
  125. if ( (perm & 1 << r) != 0) {
  126. subSet.add(in.rocks.get(r));
  127. }
  128. }
  129. subSet.add(in.finalCorner);
  130. int ways = 1;
  131. for(int subSetIdx = 1; subSetIdx < subSet.size(); ++subSetIdx )
  132. {
  133. PointInt last = subSet.get(subSetIdx-1);
  134. PointInt cur = subSet.get(subSetIdx);
  135. int m = cur.y() - last.y();
  136. int n = cur.x() - last.x();
  137. //Can only move in a positive direction +(1,0) or +(0,1)
  138. if ( m < 0 || n < 0 ) {
  139. ways = 0;
  140. break;
  141. }
  142. //Lattice paths
  143. ways *= LargeNumberUtils.combin(m+n, n, preCal, mod);
  144. ways %= mod;
  145. }
  146. //Inclusion / exclusion principal
  147. int mult = subSet.size() % 2 == 0 ? 1 : -1;
  148. totalWays += mod + mult * ways;
  149. totalWays %= mod;
  150. }
  151. return String.format("Case #%d: %d", in.testCase, totalWays);
  152. }
  153. }