lintcode573- Build Post Office II- hard

Given a 2D grid, each cell is either a wall 2, an house 1or empty 0 (the number zero, one, two), find a place to build a post office so that the sum of the distance from the post office to all the houses is smallest.

Return the smallest sum of distance. Return -1 if it is not possible.

 Notice
  • You cannot pass through wall and house, but can pass through empty.
  • You only build post office on an empty.
Example

Given a grid:

0 1 0 0 0
1 0 0 2 1
0 1 0 0 0

return 8, You can build at (1,1). (Placing a post office at (1,1), the distance that post office to all the house sum is smallest.)

Challenge 

Solve this problem within O(n^3) time.

之前题目 I 是可以直接算manhattan距离,这里不行,距离要用BFS算了。

算法主体:1.找出所有house放list  2.遍历house做bfs,把距离之和distSum[][]以及空地访问次数visitCnt[][]记录下来. 3.根据visitCnt[][]遍历合格的房子都走得到的空地,访问distSum[][]打擂台决出最小dist。

算法BFS:size的层级遍历。参数传入distSum[][]和visitCnt[][]让所有的BFS能共享这个"全局变量"进行修改。从1出发,BFS出所有的0,每次对0访问次数计数++,层级遍历的step表示从1出发到这个0的距离,让distSum[][]+=steps。另外坐标Point(x,y)这种数据结构不能用HashSet作为和queue搭配的去重set,这时候可以巧妙地自己命名一个boolean[][] hash,如果某个坐标(x,y)被加入queue了,以后不想让这个点被重复加,就赋值hash[x][y] = true; 起到了set的作用。

数据结构:distSum[][] 保存了对于地图中某个空地0,到所有房子1的距离和。  visitCnt[][] 保存了对于地图中某个空地0,能访问到多少个房子1。 

细节:1.int WALL EMPTY HOUSE=1 这种常数定义放在大类Solution里,这样保证所有子函数也能访问到这些标志。2.小心全都是房子不能放置office的corner case

public class Solution {
    /*
     * @param grid: a 2D grid
     * @return: An integer
     */
    
    private class Point{
        public int x;
        public int y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    private int WALL = 2;
    private int HOUSE = 1;
    private int EMPTY = 0;
    
    public int shortestDistance(int[][] grid) {
        // write your code here
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return -1;
        }
        

        int h = grid.length;
        int w = grid[0].length;
        
        int[][] visitCnt = new int[h][w];
        int[][] distSum = new int[h][w];
        List<Point> houses = new ArrayList<Point>();
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (grid[i][j] == HOUSE) {
                    houses.add(new Point(i,j));
                }
            }
        }
        
        for (Point p : houses) {
            bfs(grid, p, visitCnt, distSum);
        }
        
        int minDist = Integer.MAX_VALUE;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                //!!!两个条件
                if (grid[i][j] != EMPTY || visitCnt[i][j] != houses.size()) {
                    continue;
                }
                minDist = Math.min(minDist, distSum[i][j]);
            }
        }
        
        // !!!CORNER CASE : all 1 or 2
        if (minDist == Integer.MAX_VALUE) {
            return -1;
        }
        return minDist;
    }
    
    private void bfs (int[][] grid, Point crt, int[][] visitCnt, int[][] distSum) {
        int[] dx = {-1, 0, 1, 0};
        int[] dy = {0, -1, 0, 1};
        boolean[][] hash = new boolean[grid.length][grid[0].length];
        Queue<Point> queue = new LinkedList<Point>();
        
        queue.offer(crt);
        hash[crt.x][crt.y] = true;
        int steps = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Point p = queue.poll();
                visitCnt[p.x][p.y]++;
                distSum[p.x][p.y] += steps;
                for (int dirct = 0; dirct < 4; dirct++) {
                    Point next = new Point (p.x + dx[dirct], p.y + dy[dirct]);
                    // !!!三个条件不要漏
                    if (isValid(grid, next) && !hash[next.x][next.y] && grid[next.x][next.y] == EMPTY) {
                        queue.offer(next);
                        hash[next.x][next.y] = true;
                    }
                }
            }
            steps++;
        }
        
    }
    
    private boolean isValid(int[][] grid, Point point) {
        int h = grid.length;
        int w = grid[0].length;
        return point.x >= 0 && point.x < h && point.y >= 0 && point.y < w;
    }
}
原文地址:https://www.cnblogs.com/jasminemzy/p/7750017.html