专题(六) 双指针、BFS与图论——AcWing 1101. 献给阿尔吉侬的花束

【题目描述】
AcWing 1101. 献给阿尔吉侬的花束

【思路】
BFS 使用状态数组st
如果把状态数组st的代码去掉 会陷入死循环 所以在标记状态时要考虑清楚。最好是使用状态数组,比较容易理解。

import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
class Node{
    int x, y, step;
    public Node(int xx, int yy, int stepp){
        x = xx;
        y = yy;
        step = stepp;
    }
}
public class Main{
    static int R = 210;
    static int dir[][] = {{-1, 0}, {0, 1}, {1, 0}, {0, - 1}};
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int T = reader.nextInt();
        while(T-- >0){
            int r = reader.nextInt(), c = reader.nextInt();
            char[][] g= new char[R][R];
            boolean st[][] = new  boolean[R][R];
            for(int i = 0; i < r; i ++)
                g[i] = reader.next().toCharArray();
            
            int sx = 0, sy = 0;
            for(int i = 0; i < r; i ++)
                for(int j = 0; j < c; j ++)
                    if(g[i][j]=='S'){
                        sx = i;
                        sy = j;
                    }
                    
            Queue<Node> q = new LinkedList<Node>();
            q.offer(new Node(sx, sy, 0));
            st[sx][sy] = true;
            
            
            boolean f = false;
            int ans = 0;
            while(!q.isEmpty()){
                Node h = q.poll();
                int x = h.x, y = h.y, step = h.step;
                if(g[x][y] == 'E'){
                    ans = step;
                    f = true;
                    break;
                }
                g[x][y] = '#';
                //从当前位置扩展四个方向节点入队列
                for(int i = 0; i < 4; i ++){
                    int a = x +dir[i][0], b = y + dir[i][1];
                    if( a < 0 || a >=r || b < 0 || b >= c || g[a][b] == '#'||st[a][b]) continue;
                    q.offer(new Node(a, b, step + 1));
                    st[a][b] = true;
                }
                
            }
            if(f)
                System.out.println(ans);
            else
                System.out.println("oop!");
            
                
        }
    }
        
}

如果不使用状态数组st,个人比较推崇下面这种写法,在入队列时就将其标记 为访问过。否则很容易陷入死循环。

import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
class Node{
    int x, y, step;
    public Node(int xx, int yy, int stepp){
        x = xx;
        y = yy;
        step = stepp;
    }
}
public class Main{
    static int R = 210;
    static int dir[][] = {{-1, 0}, {0, 1}, {1, 0}, {0, - 1}};
    static char[][] g= new char[R][R];
    public static String bfs(int sx, int sy, int r, int c){
        
            Queue<Node> q = new LinkedList<Node>();
            q.offer(new Node(sx, sy, 0));
            g[sx][sy] = '#';
            
            while(!q.isEmpty()){
                Node h = q.poll();
                int x = h.x, y = h.y, step = h.step;
                //从当前位置扩展四个方向节点入队列
                for(int i = 0; i < 4; i ++){
                    int a = x +dir[i][0], b = y + dir[i][1];
                    if( a < 0 || a >=r || b < 0 || b >= c || g[a][b] == '#') continue;
                    if(g[a][b] == 'E') return ""+(step + 1);
                    g[a][b] = '#'; //标记已经走过
                    q.offer(new Node(a, b, step + 1));
                }
                
            }
            return "oop!";
    }
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int T = reader.nextInt();
        while(T-- >0){
            int r = reader.nextInt(), c = reader.nextInt();
            for(int i = 0; i < r; i ++)
                g[i] = reader.next().toCharArray();
            
            int sx = 0, sy = 0;
            for(int i = 0; i < r; i ++)
                for(int j = 0; j < c; j ++)
                    if(g[i][j]=='S'){
                        sx = i;
                        sy = j;
                    }
            System.out.println(bfs(sx, sy, r, c));
                    
            
        }
    }
        
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值