day03
🎉前言:每日更新!不断更!,周内一天一题.周末算法精析
✨更新地址:Royeblog
🎆🎆第十三届国赛javaB 试题 E: 迷宫
🎉题目链接:题号2222
✨简单描述题目:
【问题描述】
这天,小明在玩迷宫游戏。 迷宫为一个n * n的网格图,小明可以在格子中移动,左上角为(1; 1),右 下角(n; n) 为终点。迷宫中除了可以向上下左右四个方向移动一格以外,还有 m个双向传送门可以使用,传送门可以连接两个任意格子。 假如小明处在格子(x1; y1),同时有一个传送门连接了格子(x1; y1) 和(x2; y2),那么小明既可以花费1 的步数向上下左右四个方向之一走一格(不能 越过边界),也可以花费1 的步数通过传送门走到格子(x2; y2) 去。而对于同一个迷宫,小明每次进入的初始格子是在这n * n 个格子中均匀随机的(当然运气好可以直接随机到终点),他想知道从初始格子走到终点的最短 步数的期望值是多少。
【输入格式】
输入共1 + m行,第一行为两个正整数n;m。 后面m 行,每行四个正整数xi1; yi1; xi2; yi2 表示第i 个传送门连接的两个格子坐标。
【输出格式】
输出共一行,一个浮点数表示答案(请保留两位小数)。
【样例输入】2 1 1 1 2 2
【样例输出】
0.75
【样例解释】
由于传送门的存在,从(1; 1) 出发到终点(2; 2) 只需要一步;而从(1; 2) 和 (2; 1) 出发也只需要向下/右走一步;从(2; 2) 出发需要0 步。所以步数期望为 (1+1+1+0)/ (2*2) = 0:75。
【评测用例规模与约定】
对于20% 的数据,保证n;m <= 20; 对于100% 的数据,保证n;m <= 2000; xi1; yi1; xi2; yi2 <= n。
import java.util.*;
public class D迷宫 {
static class node {
int x;
int y;
int step;
public node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
public static void main(String[] args) {
int[] dx = {0, 0, 1, -1};
int[] dy = {1, -1, 0, 0};
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
//从n,n到该点的最低步数
int[][] arrmap = new int[n+1][n+1];
//存储传送门 从x1,y1到x2,y2
//将x1,y1以x1*n+y1的形式保存为integer 用list表示多个门传送到同一个门
Map<Integer,List<int[]>> map=new HashMap<>();
for (int i = 0; i < m; i++) {
int x1 = sc.nextInt();
int y1 = sc.nextInt();
int x2 = sc.nextInt();
int y2 = sc.nextInt();
if (!map.containsKey(x1*n+y1)){
map.put(x1*n+y1,new ArrayList<>());
}
map.get(x1*n+y1).add(new int[]{x2, y2});
//双向传送门
if (!map.containsKey(x2*n+y2)){
map.put(x2*n+y2,new ArrayList<>());
}
map.get(x2*n+y2).add(new int[]{x1, y1});
}
//经典BFS模板
Queue<node> list = new LinkedList<>();
list.add(new node(n, n, 0));
while (!list.isEmpty()) {
node pop = list.poll();
int movex,movey;
//如果有传送门就传送
if (map.containsKey(pop.x*n+ pop.y)){
for (int[] ints : map.get(pop.x * n + pop.y)) {
movex=ints[0];
movey=ints[1];
if (movey == 0) {
movex --;
movey = n;
}
if (arrmap[movex][movey]==0){
list.add(new node(movex,movey, pop.step+1));
arrmap[movex][movey]= pop.step+1;
}
}
}
//没有就遍历上下左右
for (int i = 0; i < 4; i++) {
movex= pop.x+dx[i];
movey= pop.y+dy[i];
if (movex>0&&movey>0&&movex<=n&&movey<=n&&arrmap[movex][movey]==0){
list.add(new node(movex,movey,pop.step+1));
arrmap[movex][movey]= pop.step+1;
}
}
}
int sum=0;
for (int i = 1; i < arrmap.length; i++) {
for (int j = 1; j < arrmap.length; j++) {
sum+=arrmap[i][j];
}
}
//n,n会被覆盖不为0减去就好
sum-=arrmap[n][n];
System.out.printf("%.2f",sum*1.0/(n*n));
}
}
经典BFS题,注释很清楚!主要是对于传送门的理解,是双向传送门,可以有多个门传送到同一个地方,改了好几次才ac,题本来不难,主要是对传送门处理,例如integer=x1*n+y1和用map存储多个门,加油吧少年们! 👍