首页 > 试题广场 >

迷宫

[编程题]迷宫
  • 热度指数:2211 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}给定一个 \mathrm{n \times m} 的迷宫,迷宫由 "#" 与"." 两种字符组成。其中 "#" 代表障碍物,"." 表示空地。迷宫中还有一个起点 "S" 和一个终点 "E" ,它们都可以视为空地。

\hspace{15pt}由于近期迷宫发生了塌方,导致起点和终点之间可能并不连通。幸运的是,你拥有一种超能力——在迷宫中移动时(移动方向为上、下、左、右四个方向之一),可以在当前位置朝任一方向(上、下、左、右四个方向之一)释放激光。激光能够清除该方向上所有的障碍物,并且这种超能力至多只能使用一次。

\hspace{15pt}现在,你需要判断是否能利用这种超能力成功从起点到达终点。

输入描述:
\hspace{15pt}第一行给定两个整数 \mathrm{n,m}(\mathrm{2 \leqq n,m \leqq 1000}) ,分别表示迷宫的行数和列数。
\hspace{15pt}下面 \mathrm{n} 行,每行 \mathrm{m} 个字符,描述迷宫的具体布局。字符只包含 "#"、"."、"S" 和 "E",并且起点与终点有且仅有一个。


输出描述:
\hspace{15pt}能够到达终点输出 \mathrm{YES} ;否则输出 \mathrm{NO}
示例1

输入

4 5
.####
S####
.####
.E###

输出

YES
示例2

输入

4 5
..###
S####
#####
##.E#

输出

YES

说明

显然可以从起点出发,到达\mathrm{(1,2)}处并向下方使用超能力,此时可以从起点到达终点。
示例3

输入

4 5
..###
S####
#####
###E#

输出

NO
package main

/*
   BFS
   分别从S、E出发,把可达位置分别标记为S、E
   遍历过程中判断是否有同一行/列或相邻行/列内既含有S,也含有E
*/

import (
	"fmt"
)

type Node struct {
	i, j int
}

var nS, nE, nH byte = byte('S'), byte('E'), byte('#')

func isAdjoin(a, b int) bool { // 是否相邻
    if a > b{
        return a - b <= 1
    }
    return b - a <= 1
}

func main() {
	var n, m int
	fmt.Scanf("%d %d", &n, &m)
	var k = make([][]byte, n)
	var s string
	var S_i, S_j, E_i, E_j int
	for i := 0; i < n; i++ {
		fmt.Scanf("%s", &s)
		k[i] = make([]byte, m)
		k[i] = []byte(s)
		for j := 0; j < m; j++ {
			if k[i][j] == nS {
				S_i = i
				S_j = j
			}
			if k[i][j] == nE {
				E_i = i
				E_j = j
			}
		}
	}
	if isAdjoin(S_i, E_i) || isAdjoin(S_j, E_j) { // 相邻或同行或同列
		fmt.Println("YES")
		return
	}

    var si, sj = make([]bool, n),make([]bool, m) // 记录某行某列是否S可达 
    si[S_i] = true
    sj[S_j] = true

	dist := [][]int{{1, 0}, {-1, 0}, {0, -1}, {0, 1}} // 四个方向操作
	var cur Node
	var ni, nj int
	// 先从S开始遍历
	queue := []Node{{S_i, S_j}}
	for len(queue) > 0 {
		cur = queue[0]
		queue = queue[1:]

		for _, d := range dist {
			ni = cur.i + d[0]
			nj = cur.j + d[1]
			if ni < 0 || ni >= n || nj < 0 || nj >= m || k[ni][nj] == nS || k[ni][nj] == nH {
				continue
			}
			if k[ni][nj] == nE || isAdjoin(ni, E_i) || isAdjoin(nj, E_j) { // 与E相邻或同行或同列
				fmt.Println("YES")
				return
			}
			k[ni][nj] = nS
            si[ni],sj[nj] = true, true
			queue = append(queue, Node{ni, nj})
		}
	}

	// 再从E开始遍历
	queue = []Node{{E_i, E_j}}
	for len(queue) > 0 {
		cur = queue[0]
		queue = queue[1:]

		for _, d := range dist {
			ni = cur.i + d[0]
			nj = cur.j + d[1]
			if ni < 0 || ni >= n || nj < 0 || nj >= m || k[ni][nj] == nE || k[ni][nj] == nH {
				continue
			}
			if k[ni][nj] == nS || 
                si[ni] || (ni-1>=0&&si[ni-1]) || (ni+1<n&&si[ni+1]) || 
                sj[nj] || (nj-1>=0&&sj[nj-1]) || (nj+1<m&&sj[nj+1]) { // 与S可达的位置相邻或同行或同列
				fmt.Println("YES")
				return
			}
			k[ni][nj] = nE
			queue = append(queue, Node{ni, nj})
		}
	}

    // 都没法满足,无法可达
	fmt.Print("NO")
}

发表于 2025-09-07 17:42:42 回复(0)