Kattis Problem - The Maze Makers

23 篇文章 0 订阅

Kattis Problem - The Maze Makers

原题链接

题目类型:搜索、BFS
题意

给定一个由 16 进制数据描述的迷宫,判断是否是以下四种情况之一:
1、从起点无法到达终点
2、至少存在一对点是不连通的
3、对于一对点之间不止一条简单路径
4、不存在上述 3 种情况,地图是 Ok 的

分析

题目本身并不难,只不过需要理解到如何去建图(并不是真的把迷宫画出来,这样有点繁琐)。因为迷宫中一个格子
是由一个 16 进制的数来描述,其上、右、下、左的状态由其 16 进制数对应位置的二进制位(高位到低位)来表示,1 代表是墙、0 代表是通路。而具体某个方向的状态可以通过 num ≫ x & 1 (0 ≤ x ≤ 3 ) 来获得。题目的具体实现可以使用BFS 实现 FloodFill 算法。如果算法结束后终点未被标记则属于情况 1,如果存在未被标记的点则属于情况 2,如果在BFS 过程中搜索到一个已经被标记的点则说明存在一对点之间不止一条简单路径属于情况 3,如果都不属于以上情况则说明地图是 Ok 的!在判断情况 3 的时候需要注意,需要对入队的点再记录一个放置它回退的信息,防止错误判断。因为如果不进行标记下次通过这个点进行转移的时候发生回退则会认为存在情况 3,但是这不属于一条简单路径。

代码
static byte[][] G;
static boolean[][] vis;
static int H, W;
static boolean multiple;

public static void solve() throws IOException {
    while (true) {
        H = nextInt();
        W = nextInt();
        
        if (H == 0 && W == 0) return ;
        
        init(H, W);
        
        for (int i = 0; i < H; i++) {
            char[] c = next().toCharArray();
            for (int j = 0; j < W; j++) G[i][j] = getNum(c[j]);
        }

        int[] XX = new int[2];
        int[] YY = new int[2];
        int idx = 0;
        for (int i = 0; i < H; i++) {
            if ((G[i][0] & 1) == 0) {
                XX[idx] = i;
                YY[idx] = 0;
                idx++;
            } else if ((G[i][W - 1] >> 2 & 1) == 0) {
                XX[idx] = i;
                YY[idx] = W - 1;
                idx++;
            }
        }
        
        for (int i = 0; i < W; i++) {
            if ((G[0][i] >> 3 & 1) == 0) {
                XX[idx] = 0;
                YY[idx] = i;
                idx++;
            } else if ((G[H - 1][i] >> 1 & 1) == 0) {
                XX[idx] = H - 1;
                YY[idx] = i;
                idx++;
            }
        }
        
        bfs(XX[0], YY[0]);
        
        if (!vis[XX[0]][YY[0]] || !vis[XX[1]][YY[1]]) {
            pw.println("NO SOLUTION");
            continue ;
        }
        
        boolean ok = true;
        for (int i = 0; i < H; i++)
            for (int j = 0; j < W; j++)
                if (!vis[i][j]) ok = false;
        
        if (!ok) {
            pw.println("UNREACHABLE CELL");
            continue ;
        }
        
        if (multiple) {
            pw.println("MULTIPLE PATHS");
            continue ;
        }
        
        pw.println("MAZE OK");
    }
} 

static final int[] dx = {0, 1, 0, -1};
static final int[] dy = {-1, 0, 1, 0};

public static void bfs(int x, int y) {
    Deque<Node> q = new ArrayDeque<>();
    q.add(new Node(x, y, -1));
    vis[x][y] = true;
    
    while (!q.isEmpty()) {
        Node e = q.poll();
        
        for (int i = 0; i < 4; i++) {
            if (i == e.back || (G[e.x][e.y] >> i & 1) == 1) continue ;
            
            int nx = e.x + dx[i];
            int ny = e.y + dy[i];
            
            if (check(nx, ny)) {
                vis[nx][ny] = true;
                q.add(new Node(nx, ny, back(i)));
            }
        }
    }
}

public static boolean check(int x, int y) {
    if (x < 0 || x >= H || y < 0 || y >= W) return false;
    if (vis[x][y]) {
        multiple = true;
        return false;
    }
    return true;
}

public static int back(int k) {
    if (k == 0) return 2;
    if (k == 1) return 3;
    if (k == 2) return 0;
    if (k == 3) return 1;
    return 0;
}

public static byte getNum(char c) {
    if (Character.isDigit(c)) return (byte) (c - '0');
    else return (byte) (c - 'A' + 10);
}

public static void init(int H, int W) {
    multiple = false;
    G = new byte[H][W];
    vis = new boolean[H][W];
}


/*******************************************************************************************************************************/

static class Node {
    int x, y;
    int back;
    
    public Node(int x, int y, int back) {
        this.x = x;
        this.y = y;
        this.back = back;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值