第六届蓝桥杯国赛JAVA语言B组第四题 穿越雷区 bfs 位运算

8 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述

说一下我在时间复杂度上的优化,总共2点

  1. 不使用类,使用int代表x,y,正副三种状态
  2. 从终点走到起点,而不是从起点走到终点

解释一下为什么不用类,因为不想用,所以不用。
一个int型的数的数值长度占了31位,我通过二进制取数值的第30位判断当前节点是+还是-。如果第30位是1,那么就是+,否则就是-
坐标通过一个公式转换 y * n + x 这个公式可以将二维的数组转为一维的数组,我们每次访问二维数组,都需要先访问Array[] 然后在Array[]里找到[] ,通过下标找到对应元素,这样子等于访问了两次对象。而使用公式转换后的下标,可以省去一次访问元素的代价。
因为是最短路径,bfs每次寻找周围一圈,如果最先能得到的路径肯定是最优路径,所以选择bfs,本题使用dfs可能会比bfs慢点,因为bfs需要把每条路径的长度最后进行一个比较,输出最短的那一条,慢就慢在这里。

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        char[][] grid = new char[n][n];
        scanner.nextLine(); // 吸收掉回车
        int startHash = 0;
        int endHash = 0;
        for (int i = 0; i < n; i++) {
            String[] s = scanner.nextLine().split(" ", n);
            for (int j = 0; j < n; j++) {
                char c = grid[i][j] = s[j].charAt(0);
                if (c == 'A') {
                    startHash = i * n + j;
                } else if (c == 'B') {
                    endHash = i * n + j;
                }
            }
        }
        /*for (char[] c : grid) {
            System.out.println(Arrays.toString(c));
        }*/
        boolean[] viewed = new boolean[n * n]; // bfs必备表示是否访问过的数组
        Queue<Integer> queue = new LinkedList<>();
        // 手动加入终点一圈的节点 并且viewed
        // 是否为正负 -> 根据 1 << 30 是否等于1决定
        int bx = endHash % n;
        int by = endHash / n;
        viewed[endHash] = true;
        if (bx + 1 < n) {
            int hashx1 = endHash + 1;
            viewed[hashx1] = true;
            if (checkPosNeg(bx+1,by,grid)) {
                hashx1 |= 1 << 30;
            }
            queue.offer(hashx1);
        }
        if (bx - 1 > -1) {
            int hash1x = endHash - 1;
            viewed[hash1x] = true;
            if (checkPosNeg(bx-1,by,grid)) {
                hash1x |= 1 << 30;
            }
            queue.offer(hash1x);
        }
        if (by + 1 < n) {
            int hashy1 = endHash + n;
            viewed[hashy1] = true;
            if (checkPosNeg(bx,by+1,grid)) {
                hashy1 |= 1 << 30;
            }
            queue.offer(hashy1);
        }
        if (by - 1 > -1) {
            int hash1y = endHash - n;
            viewed[hash1y] = true;
            if (checkPosNeg(bx,by-1,grid)) {
                hash1y |= 1 << 30;
            }
            queue.offer(hash1y);
        }
        int pathLength = 0;
        while (!queue.isEmpty()) {
            pathLength ++;
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                int hash = queue.poll();
                boolean pos = (hash & (1 << 30)) > 0;
                if (pos) {
                    hash &= (1 << 30) - 1;
                }
                if (hash == startHash) {
                    System.out.println(pathLength);
                    System.exit(0);
                }
                int x = hash % n;
                int y = hash / n;


                if (x + 1 < n && !viewed[hash+1] && (pos != (grid[y][x+1] == '+') || grid[y][x+1] == 'A')) {
                    int hashx1 = hash + 1;
                    viewed[hashx1] = true;
                    if (checkPosNeg(x+1,y,grid)) {
                        hashx1 |= 1 << 30;
                    }
                    queue.offer(hashx1);
                }
                if (x - 1 > -1 && !viewed[hash-1] && (pos != (grid[y][x-1] == '+') || grid[y][x-1] == 'A')) {
                    int hash1x = hash - 1;
                    viewed[hash1x] = true;
                    if (checkPosNeg(x-1,y,grid)) {
                        hash1x |= 1 << 30;
                    }
                    queue.offer(hash1x);
                }
                if (y + 1 < n && !viewed[hash+n] && (pos != (grid[y+1][x] == '+') || grid[y+1][x] == 'A')) {
                    int hashy1 = hash + n;
                    viewed[hashy1] = true;
                    if (checkPosNeg(x,y+1,grid)) {
                        hashy1 |= 1 << 30;
                    }
                    queue.offer(hashy1);
                }
                if (y - 1 > -1 && !viewed[hash-n] && (pos != (grid[y-1][x] == '+') || grid[y-1][x] == 'A')) {
                    int hash1y = hash - n;
                    viewed[hash1y] = true;
                    if (checkPosNeg(x,y-1,grid)) {
                        hash1y |= 1 << 30;
                    }
                    queue.offer(hash1y);
                }
            }
        }
        System.out.println(-1);
    }

    public static boolean checkPosNeg(int x, int y, char[][] grid) {
        return grid[y][x] == '+';
    }
}

自己写的测试数据:

5
A - - + -
+ + - - +
- - - + -
- - - - +
B - - + -
sout:-1

5
A - - + -
+ + - - +
- - - + -
+ - - - +
B - - + -
sout: 4
5
A - + - +
+ + - + -
- - + - +
- - + - -
B - + - +
sout: 12

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯是全国性的计算机竞赛,要想在蓝桥杯中获得优异的成绩,掌握并理解一些重要的算法对于参赛者来说是必不可少的。以下是一些蓝桥杯中必须掌握的经典算法之一:java语言实现。 1. 前缀和算法:前缀和算法是一种处理数区间和问的有效方法。通过预处理数,可以在O(1)的时间复杂度内计算任意一个区间的和。在蓝桥杯中,这种算法通常用于解决与计算区间和相关的问。 2. 深度优先搜索(DFS):DFS是一种常用的图遍历算法,用于搜索图中所有可能的路径或者寻找与某个条件匹配的路径。在蓝桥杯中,DFS经常用于解决图论或者迷宫类问。 3. 宽度优先搜索(BFS):BFS也是一种图遍历算法,与DFS不同的是,BFS是逐层遍历图,先访问离起点最近的节点,再访问离起点更远的节点。在蓝桥杯中,BFS常用于解决最短路径、迷宫类问等。 4. 动态规划(DP):动态规划是一种通过将问分解为较小的子问来解决复杂问的方法。通过保存子问的解,避免重复计算,可以大大提高计算效率。在蓝桥杯中,动态规划通常用于解决最优化问。 5. 贪心算法:贪心算法是一种在每个阶段选择当时看起来最优的策略,以希望最终结果也是最优的算法。贪心算法常用于求解最优化问,例如最小生成树、背包问等。 以上是蓝桥杯中必须掌握的一些经典算法,并给出了java语言实现的简要说明。当然,要在蓝桥杯中取得好成绩,不仅仅要掌握这些算法,还需要灵活应用和不断练习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值