2021.04.13找绿洲
题目描述
求方格地图中所有格子到出口(多个)的最小和。描述如下:
一个叫Andy的小朋友在一个正方形的沙漠中迷路了,身边的水也喝完了。Andy知道自己要渴死了,闲得无聊,所以他开始计算一些有趣的问题。
这个沙漠是由一个n*n的网格图构成的,当你站在某一个格子时,你可以走向周围八个格子中的一个。然而,沙漠中的某些格子有毒蛇,你必须避开他们,某些格子有水源,水源就是生命。
现在,Andy希望计算出每个格子到最近的水源的距离。你只需计算出所有距离的和即可。
输入格式
输入的第一行包含三个整数n, m,p,n表示沙漠的边长。m表示毒蛇的个数,p表示绿洲的个数。
接下来m行,输入m个毒蛇的坐标。一行一个
在接下来p行,输入p个绿洲的坐标。一行一个
输出格式
输出一个数,表示沙漠中每个坐标上避开毒蛇,找到绿洲的最短路径长度之和。
若坐标上有毒蛇,或无法从此坐标出发找到绿洲,长度记为-1.
若此坐标上有绿洲,长度记为0.
样例输入
3 1 2
2 1
1 3
3 2
样例输出
6
数据规模和约定
对于60%的数据,0<p<=5。
对于100%的数据,0<n<=3000, 0<p<=3000
思路
使用BFS广搜,可以从绿洲向四周搜索,因为绿洲有多个,所以初始化队列时装入多个状态。
注:以下代码不能AC(60分),望各位朋友解答。
代码
int MAX_LEN = 3002;
class Node{
Node(int x, int y, int sco) {
super();
this.x = x;
this.y = y;
this.sco = sco;
}
int x, y;
int sco;
}
int n, m, p;
int[][] dp = new int[MAX_LEN][MAX_LEN];
boolean[][] vis;
int[][] dir = {
{1,0},
{-1,0},
{0,1},
{0,-1},
{1,1},
{-1,1},
{1,-1},
{-1,-1},
};
Queue<Node> queue = new LinkedList<>();;
boolean isIn(int i, int j) {
return i>=1&&i<=n&&j>=1&&j<=n;
}
void test() throws IOException {
Reader cin = new Reader();
n = cin.nextInt();
m = cin.nextInt();
p = cin.nextInt();
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dp[i][j] = Integer.MAX_VALUE;
for(int i = 0; i < m; i++) { //标记毒蛇
int x = cin.nextInt(), y = cin.nextInt();
dp[x][y] = -1;
}
for(int i = 0; i < p; i++) { //标记绿洲
int x = cin.nextInt(), y = cin.nextInt();
dp[x][y] = 0;
queue.add(new Node(x, y, 0));
}
vis = new boolean[MAX_LEN][MAX_LEN];
while(!queue.isEmpty()) { // 当队列不为空时
Node cur = queue.poll();
for(int k = 0; k < dir.length; k++) {
int nx = cur.x+dir[k][0];
int ny = cur.y+dir[k][1];
int len = cur.sco+1;
if(isIn(nx, ny) && !vis[nx][ny] && dp[nx][ny]!=-1 && len<dp[nx][ny]) {
dp[nx][ny] = len;
Node newNode = new Node(nx, ny, len);
vis[nx][ny] = true;
queue.add(newNode);
}
}
}
int s = 0;
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(dp[i][j] != -1) {
if(dp[i][j] != Integer.MAX_VALUE)
s += dp[i][j];
else s--;
}
System.out.println(s-m);
}