胜利大逃亡(广度优先搜素BFS)

该博客讨论了一个在A*B*C立方体中,Ignatius从(0,0,0)出发到(A-1,B-1,C-1)的逃亡问题。利用广度优先搜索(BFS)算法,求解在给定时间T内是否能成功逃出立方体。文章提供了一组样例输入和相应的输出,并给出了示例代码来说明解决方案。" 139127894,17663336,2024华为OD机试:C++解密算法实战,"['华为od', 'C++', '算法', '开发语言']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

    一个A*B*C的立方体,Ignatius被困在其中(0,0,0)的位置,离开立方体的门在(A-1,B-1,C-1)位置。在给定时间T内,若Ignatius能够离开立方体,则逃亡成功。如果可以输出逃亡时间,否则输出-1.

输入:

    输入数据的第一行是一个正整数K,表名测试数据的数量。每组测试数据的第一行是四个正整数A,B,C和T,(1<=A,B,C<=50,1<=T<=1000),它们分别代表立方体的大小和规定时间,然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表立方体的布局,其中0代表路,1代表墙。

输出:

    对于每组测试数据,如果Ignatius能在T时间内(包含T)离开,则输出需要的时间,否则输出-1.

样例输入:

    1
    3 3 4 20
    0 1 1 1 
    0 0 1 1
    0 1 1 1
    1 1 1 1
    1 0 0 1  
    0 1 1 1
    0 0 0 0
    0 1 1 0
    0 1 000

样例输出:

    11

示例代码:

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    public static int costTime(boolean[][][] isVisited,boolean[][][] isWay,int A,int B,int C){
        Queue<Point_time> pt = new LinkedList<>();//为了实现各个状态按其被查找到的顺序依次进行扩展,
        // 使用队列将每次扩展得到的新结点加入队列,待排在其之前的状态都被扩展完成之后,该状态才能得到扩展
        Point_time start = new Point_time(0, 0, 0, 0);
        pt.offer(start);
        while (!pt.isEmpty()){
            Point_time ptToexplore = pt.peek();
            int x = ptToexplore.x;
            int y = ptToexplore.y;
            int z = ptToexplore.z;
            isVisited[x][y][z] = true;
            int t = ptToexplore.t;
            if (x==A-1&&y==B-1&&z==C-1){return t;}
            if (!isWay[x][y][z]){pt.poll();continue;}//如果是墙,则不需要扩展,将此结点从队列中删去
            int x1 = x - 1;
            int x2 = x + 1;
            int y1 = y - 1;
            int y2 = y + 1;
            int z1 = z - 1;
            int z2 = z + 1;
            t++;
            if (x > 0) {
                if (!isVisited[x1][y][z]){//当加入某一结点时,先判断此结点有没有被扩展过。
                    // 扩展过的结点t值<=将要扩展的此结点值(在树的同一层时相等,在不同层时,小于),故若扩展过,不将此结点加入队列,即进行剪枝
                pt.offer(new Point_time(x1, y, z, t));}}
            if (x<A-1) {
                if (!isVisited[x2][y][z]){
                pt.offer(new Point_time(x2, y, z, t));}}
            if (y > 0) {
                if (!isVisited[x][y1][z]){
                pt.offer(new Point_time(x, y1, z, t));}}
            if (y<B-1) {
                if (!isVisited[x][y2][z]){
                pt.offer(new Point_time(x, y2, z, t));}}
            if ( z> 0) {
                if (!isVisited[x][y][z1]){
                pt.offer(new Point_time(x, y, z1, t));}}
            if (z<C-1) {
                if (!isVisited[x][y][z2]){
                pt.offer(new Point_time(x, y, z2, t));}}
            pt.poll();//将拓展过的结点从待处理队列中删除
        }
        return -1;//若遍历完所有在queue中的结点,仍没有访问到[A-1][B-1][C-1],则返回-1
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int count = scanner.nextInt();
            for (int cnt = 0; cnt < count; cnt++) {
                int A = scanner.nextInt();
                int B = scanner.nextInt();
                int C = scanner.nextInt();
                boolean[][][] isWay = new boolean[A][B][C];//记录每个点是否是路
                boolean[][][] isVisited = new boolean[A][B][C];//记录每个点是否被访问过,
                // 若结点被访问过,则不再进行扩展,实际上达到了剪枝的目的
                int T = scanner.nextInt();
                for (int a = 0; a < A; a++) {
                    for (int b = 0; b < B; b++) {
                        for (int c = 0; c < C; c++) {
                            isWay[a][b][c] = scanner.nextInt() == 0;
                        }
                    }
                }
                int cost_time = costTime(isVisited,isWay,A,B,C);
                if (cost_time<=T){System.out.println(cost_time);}
                else {System.out.println(-1);}
            }
        }
    }
}



public class Point_time {
    int x,y,z;//三维空间中点的坐标
    int t;//从[0][0][0]到该点的时间t
    public Point_time(int x,int y,int z,int t){
        this.x = x;
        this.y = y;
        this.z = z;
        this.t = t;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值