Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.BufferedReader;
- import java.io.FileReader;
- import java.util.*;
- public class Code20B {
- public static void main(String[] args) {
- List<String> file;
- try (
- BufferedReader in = new BufferedReader(new FileReader(args[0]))
- ) {
- file = in.lines().collect(Collectors.toList());
- } catch (Exception e) {
- return;
- }
- LPAGrid grid = new LPAGrid(file);
- int count = 0;
- int LIMIT = 100;
- int RADIUS = 50;
- List<Point> offsets = new ArrayList<>();
- for (int r = -RADIUS; r <= RADIUS; r++) {
- for (int c = Math.abs(r) - RADIUS; c <= RADIUS - Math.abs(r); c++) {
- if (r != 0 || c != 0) {
- offsets.add(new Point(r, c));
- }
- }
- }
- for (int r = 1; r < grid.rows - 1; r++) {
- for (int c = 1; c < grid.columns - 1; c++) {
- Point p1 = new Point(r, c);
- if (!grid.isWall(p1)) {
- for (Point offset : offsets) {
- Point p2 = p1.add(offset);
- int savings = grid.getDist(p2) - grid.getDist(p1) - Math.abs(offset.r) - Math.abs(offset.c);
- if (!grid.isWall(p2) && savings >= LIMIT) {
- System.out.printf("Found cheat! (%d, %d) -> (%d, %d), with length %d\n", p1.r, p1.c, p2.r, p2.c, savings);
- count++;
- }
- }
- }
- }
- }
- System.out.println(count);
- }
- }
- public class LPAGrid {
- private int[][] walls;
- private int[][] dist;
- private int[][] exp;
- private final int INFINITY;
- private LPAQueue queue = new LPAQueue();
- private final Point[] DIRECTIONS = {Point.UP, Point.DOWN, Point.LEFT, Point.RIGHT};
- public Point start = new Point(0,0);
- public Point end = null;
- public final int rows;
- public final int columns;
- private class LPAQueue extends PriorityQueue<Point> {
- public LPAQueue() {
- super((a,b) -> LPAGrid.this.getScore(a) - LPAGrid.this.getScore(b));
- }
- public boolean hasNext() {
- if (this.isEmpty()) {
- return false;
- }
- return !LPAGrid.this.isConsistent(LPAGrid.this.end) ||
- LPAGrid.this.getScore(LPAGrid.this.end) >= LPAGrid.this.getScore(this.peek());
- }
- }
- public LPAGrid(int rows, int columns) {
- this.rows = rows;
- this.columns = columns;
- this.walls = new int[rows][columns];
- this.dist = new int[rows][columns];
- this.exp = new int[rows][columns];
- this.end = new Point(rows - 1, columns - 1);
- this.INFINITY = 2 * rows * columns;
- for (int r = 0; r < this.rows; r++) {
- for (int c = 0; c < this.columns; c++) {
- this.dist[r][c] = this.exp[r][c] = r+c;
- }
- }
- }
- public LPAGrid(List<String> file) {
- this.rows = file.size();
- this.columns = file.get(0).length();
- this.walls = new int[rows][columns];
- this.dist = new int[rows][columns];
- this.exp = new int[rows][columns];
- this.INFINITY = 2 * rows * columns;
- for (int r = 0; r < this.rows; r++) {
- for (int c = 0; c < this.columns; c++) {
- switch (file.get(r).charAt(c)) {
- case 'S':
- this.walls[r][c] = 0;
- this.exp[r][c] = 0;
- this.dist[r][c] = this.INFINITY;
- this.start = new Point(r, c);
- break;
- case 'E':
- this.end = new Point(r, c);
- // Fall through, because apart from setting this.end, it's otherwise a normal free space
- case '.':
- this.walls[r][c] = 0;
- this.exp[r][c] = this.INFINITY;
- this.dist[r][c] = this.INFINITY;
- break;
- case '#':
- this.walls[r][c] = 1;
- break;
- }
- }
- }
- this.queue.add(start);
- this.update();
- }
- private void update() {
- while (this.queue.hasNext()) {
- Point curr = this.queue.poll();
- if (this.getDist(curr) > this.getExp(curr)) {
- this.setDist(curr, this.getExp(curr));
- } else if (this.getDist(curr) < this.getExp(curr)) {
- this.setDist(curr, this.INFINITY);
- if (!this.isConsistent(curr)) {
- this.queue.remove(curr);
- this.queue.add(curr);
- }
- }
- }
- }
- public void inspect() {
- for (int r = 0; r < this.rows; r++) {
- for (int c = 0; c < this.columns; c++) {
- if (this.isWall(new Point(r,c))) {
- System.out.print(" ");
- } else {
- System.out.printf("%2d ", this.dist[r][c]);
- }
- }
- System.out.println();
- }
- }
- private boolean isInBounds(Point p) {
- return p.r >= 0 && p.r < this.rows && p.c >= 0 && p.c < this.columns;
- }
- public boolean isWall(Point p) {
- return !this.isInBounds(p) || this.walls[p.r][p.c] == 1;
- }
- public int getDist(Point p) {
- if (!this.isInBounds(p) || this.isWall(p)) {
- return this.INFINITY;
- }
- return this.dist[p.r][p.c];
- }
- private int getExp(Point p) {
- if (!this.isInBounds(p) || this.isWall(p)) {
- return this.INFINITY;
- }
- return this.exp[p.r][p.c];
- }
- private int getScore(Point p) {
- if (!this.isInBounds(p) || this.isWall(p)) {
- return this.INFINITY;
- }
- return Math.min(this.dist[p.r][p.c], this.exp[p.r][p.c]);
- }
- private boolean isConsistent(Point p) {
- if (!this.isInBounds(p) || this.isWall(p)) {
- return true;
- }
- return this.dist[p.r][p.c] == this.exp[p.r][p.c];
- }
- private void setDist(Point p, int dist) {
- if (!this.isInBounds(p) || this.isWall(p) || this.getDist(p) == dist) {
- return;
- }
- this.dist[p.r][p.c] = dist;
- for (Point dir : this.DIRECTIONS) {
- this.updateExp(p.add(dir));
- }
- this.queue.remove(p);
- this.queue.add(p);
- }
- private void updateExp(Point p) {
- if (!this.isInBounds(p) || this.isWall(p) || p.equals(this.start)) {
- return;
- }
- int minDist = this.INFINITY;
- for (Point dir : this.DIRECTIONS) {
- int test = this.getDist(p.add(dir)) + 1;
- if (test < minDist && !isWall(p.add(dir))) {
- minDist = test;
- }
- }
- if (this.exp[p.r][p.c] != minDist) {
- this.exp[p.r][p.c] = minDist;
- this.queue.remove(p);
- this.queue.add(p);
- }
- }
- public boolean addWall(Point p) {
- if (this.isInBounds(p) && !this.isWall(p)) {
- this.walls[p.r][p.c] = 1;
- for (Point dir : this.DIRECTIONS) {
- this.updateExp(p.add(dir));
- }
- this.queue.remove(p);
- this.update();
- }
- return this.getDist(this.end) < this.INFINITY;
- }
- }
- public class Point {
- public static Point UP = new Point(-1,0);
- public static Point DOWN = new Point(1,0);
- public static Point LEFT = new Point(0,-1);
- public static Point RIGHT = new Point(0,1);
- public final int r, c;
- public Point(int r, int c) {
- this.r = r;
- this.c = c;
- }
- public Point add(Point p) {
- return new Point(p.r + this.r, p.c + this.c);
- }
- public int dist(Point p) {
- return Math.abs(this.r - p.r) + Math.abs(this.c - p.c);
- }
- public Point ccw() {
- return new Point(-this.c, this.r);
- }
- public Point cw() {
- return new Point(this.c, -this.r);
- }
- public boolean equals(Object obj) {
- if (obj instanceof Point) {
- return ((Point) obj).r == this.r && ((Point) obj).c == this.c;
- } else {
- return false;
- }
- }
- public int hashCode() {
- return Objects.hash(this.c, this.r);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement