AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

bfs——flood fill模型和单元最短路径问题

作者: 作者的头像   二木先生 ,  2024-10-29 15:23:58 ,  所有人可见 ,  阅读 7


0


Flood Fille 模型

所有边权重相同的图,可以在线性时间内,查找到所有的连通块。

求最小的…
bfs基于迭代实现,因此不会曝栈,但是大概率可能会超时。

例题:
1. 池塘计数
2. 山峰和山谷
3. 城堡问题

会遍历所有的点,bfs

代码样例 池塘计数

package flood_fill

import "fmt"

var (
    M int
    N int
)

// FloodFill1097 池塘计数
func FloodFill1097() {
    _, _ = fmt.Scanln(&N, &M)

    arr := make([]string, N)
    for i := 0; i < N; i++ {
        _, _ = fmt.Scan(&arr[i])
    }

    cnt := 0

    // 是否访问过该节点 state 的缩写
    st := make([][]bool, N)
    for i := 0; i < N; i++ {
        st[i] = make([]bool, M)
    }

    for i := 0; i < N; i++ {
        for j := 0; j < M; j++ {
            // 若该节点有水,且未访问过,从该节点开始宽搜
            if arr[i][j] == 'W' && !st[i][j] {
                bfs(&arr, i, j, &st)
                cnt++
            }
        }
    }

    fmt.Println("count:", cnt)
}

func bfs(arr *[]string, rl int, rr int, st *[][]bool) {
    type node []int
    var queue []node
    var l, r int
    queue = append(queue, node{rl, rr})
    for len(queue) > 0 {
        cur := queue[0]
        queue = queue[1:]
        l = cur[0]
        r = cur[1]
        // 遍历当前节点的周围节点, 八连通
        for i := -1; i <= 1; i++ {
            for j := -1; j <= 1; j++ {
                // 当前位置
                if i == 0 && j == 0 {
                    continue
                }
                // 超出边界
                if l+i < 0 || l+i >= N || r+j < 0 || r+j >= M {
                    continue
                }
                // 若是土地或已经访问过
                if (*arr)[l+i][r+j] == '.' || (*st)[l+i][r+j] {
                    continue
                }
                (*st)[l+i][r+j] = true
                // 进队
                queue = append(queue, node{l + i, r + j})
            }
        }
    }
}

单元最短路径问题

从指定点触发,通过bfs的性质,找到达到目的点的最短路径或最短距离

  • 最短路径可以通过指定path[i,j],存储上一跳的位置
  • 最短距离可以通过dist[i,j],存储上一条的距离,或者说次数

例题:
- 迷宫问题,求最短路径
- 武士风度的牛,求最短距离
- 抓住那头牛

代码样例,忽略风格

// 午时风度的牛
package min_path

import "fmt"

type node []int

// Knight 武士风度的牛
func Knight() {
    var c, r int

    _, _ = fmt.Scanln(&c, &r)

    // 处理输入
    arr := make([]string, r)
    for i := 0; i < r; i++ {
        _, _ = fmt.Scanln(&arr[i])
    }

    // 查找起始点
    // 起点终点
    var start node

    for i := 0; i < r; i++ {
        for idx, elem := range arr[i] {
            if elem == 'K' {
                start = node{i, idx}
                break
            }
        }
    }

    distance := dfsKnight(arr, start, c, r)

    fmt.Println(distance)
}

func dfsKnight(arr []string, start node, c int, r int) int {
    // dx dy
    dx := []int{-1, 1, -2, 2, -2, 2, -1, 1}
    dy := []int{-2, -2, -1, -1, 1, 1, 2, 2}

    // 需要求至少要跳多少次
    dist := make([][]int, r)
    for i := 0; i < r; i++ {
        dist[i] = make([]int, c)
        for j := 0; j < c; j++ {
            dist[i][j] = -1
        }
    }
    // 队列
    var queue []node
    queue = append(queue, start)
    dist[start[0]][start[1]] = 0

    // 从start节点开始bfs
    for len(queue) > 0 {
        // 出队
        current := queue[0]
        queue = queue[1:]
        x := current[0]
        y := current[1]

        for i := 0; i < len(dx); i++ {
            tx := x + dx[i]
            ty := y + dy[i]
            // 越界
            if tx < 0 || tx >= r || ty < 0 || ty >= c {
                continue
            }
            // 障碍物
            if arr[tx][ty] == '*' {
                continue
            }
            // 若已经访问过
            if dist[tx][ty] >= 0 {
                continue
            }
            dist[tx][ty] = dist[x][y] + 1
            queue = append(queue, node{tx, ty})
            // 若是终点
            if arr[tx][ty] == 'H' {
                // print(dist)
                return dist[tx][ty]
            }
        }
    }
    return -1
}

func print(dist [][]int) {
    for _, row := range dist {
        for _, val := range row {
            fmt.Printf("\t%d", val)
        }
        fmt.Println()
    }
    fmt.Println("------------------------------------")
}

// 城堡问题
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;

public class T1076 {
    private class Node {
        int x;

        int y;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

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

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

    public void Labyrinth() {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        int[][] arr = new int[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                arr[i][j] = scanner.nextInt();
            }
        }

        // 前一个节点
        Node[][] previous = new Node[n][n];

        bfs(arr, previous);

        List<Node> ans = new LinkedList<>();
        Node pre = new Node(n - 1, n - 1);
        ans.add(pre);

        do {
            pre = previous[pre.x][pre.y];
            ans.add(pre);
        } while (pre.x != 0 || pre.y != 0);

        for (int i = ans.size() - 1; i >= 0; i--) {
            System.out.println(ans.get(i).x + " " + ans.get(i).y);
        }
    }

    // 从左上,到右下,假设必定有解
    private void bfs(int[][] arr, Node[][] previous) {
        Queue<Node> queue = new LinkedList<>();
        queue.offer(new Node(0, 0));
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            int x = cur.x;
            int y = cur.y;

            for (int i = 0; i < 4; i++) {
                int tx = x + dx[i];
                int ty = y + dy[i];
                // 数组越界
                if (tx < 0 || ty < 0 || tx >= arr.length || ty >= arr[0].length) {
                    continue;
                }
                // 墙壁或者已经访问过
                if (arr[tx][ty] == 1 || previous[tx][ty] != null) {
                    continue;
                }
                // visit
                previous[tx][ty] = cur;

                // 遍历到右下角
                if (tx == arr.length - 1 && ty == arr[0].length - 1) {
                    return;
                }

                queue.offer(new Node(tx, ty));
            }
        }
    }

    public static void main(String[] args) {
        new T1076().Labyrinth();
    }
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息