배추 지렁이는 인접한 배추들을 이동하며 해충을 잡아 먹는다
밭 군데군데 배추를 심어뒀기 때문에 배추 벌레가 이동할 수 없는 공간이 존재한다
배추밭 전체를 보호하기 위해 필요한 배추 지렁이는 몇마리인가?
-> BFS 기본 유형
가로 세로 바꿔 풀어서 약간 헷갈렸다
import java.io.*
import java.util.*
lateinit var graph: Array<IntArray>
lateinit var visited: Array<BooleanArray>
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val t = readLine().toInt()
val bw = BufferedWriter(OutputStreamWriter(System.out))
repeat(t) {
var st = StringTokenizer(readLine())
val m = st.nextToken().toInt()
val n = st.nextToken().toInt()
val k = st.nextToken().toInt()
graph = Array(n) { IntArray(m) { 0 } }
visited = Array(n) { BooleanArray(m) { false } }
// 탐색할 그래프 만들기
repeat(k) {
st = StringTokenizer(readLine())
val x = st.nextToken().toInt()
val y = st.nextToken().toInt()
graph[y][x] = 1
}
// bfs
var count = 0
for (row in 0 until n) {
for(col in 0 until m) {
if (visited[row][col] || graph[row][col] == 0) continue
bfs(n, m, col, row)
count++
}
}
bw.write("$count\n")
}
bw.close()
}
fun bfs(n: Int, m: Int, startX: Int, startY: Int) {
val queue = ArrayDeque<Move>()
val dx = arrayOf(0, 0, -1, 1)
val dy = arrayOf(1, -1, 0, 0)
visited[startY][startX] = true
queue.add(Move(startX, startY))
while (queue.isNotEmpty()) {
val current = queue.remove()
for (i in 0 until 4) {
val nx = current.x + dx[i]
val ny = current.y + dy[i]
if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue
if (visited[ny][nx] || graph[ny][nx] == 0) continue
visited[ny][nx] = true
queue.add(Move(nx, ny))
}
}
}
data class Move(val x: Int, val y: Int)
적록색약이 아닌 경우와 적록색약인 경우로 나눠서 총 bfs를 두번 진행한다
적록색약인 경우에는 R과 G를 같은 값으로 취급하는 조건문을 넣어준다
import java.io.*
import java.util.*
lateinit var graph: Array<CharArray>
lateinit var visited1: Array<BooleanArray>
lateinit var visited2: Array<BooleanArray>
private val dx = arrayOf(1, -1, 0, 0)
private val dy = arrayOf(0, 0, -1, 1)
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val n = readLine().toInt()
graph = Array(n) { CharArray(n) { 'A' } }
visited1 = Array(n) { BooleanArray(n) { false } }
visited2 = Array(n) { BooleanArray(n) { false } }
// 1. 그래프 채우기
for (i in 0 until n) {
val string = readLine()
var j = 0
for (c in string) {
graph[i][j++] = c
}
}
val bw = BufferedWriter(OutputStreamWriter(System.out))
var count = 0
// 2. 적록색약이 아닌 사람이 봤을 때
for (i in 0 until n) {
for (j in 0 until n) {
if (visited1[i][j]) continue
bfs(n, i, j, visited1, false)
count++
}
}
bw.write("$count ")
count = 0
// 3. 적록색약인 사람이 봤을때
for (i in 0 until n) {
for (j in 0 until n) {
if (visited2[i][j]) continue
bfs(n, i, j, visited2, true)
count++
}
}
bw.write("$count")
bw.close()
}
private fun bfs(n: Int, startR: Int, startC: Int, visited: Array<BooleanArray>, isColorWeakness: Boolean) {
val queue = ArrayDeque<Move>()
val c = graph[startR][startC]
visited[startR][startC] = true
queue.add(Move(startR, startC))
while (queue.isNotEmpty()) {
val current = queue.remove()
for (i in 0 until 4) {
val nx = current.x + dx[i]
val ny = current.y + dy[i]
if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue
if (visited[nx][ny] || !check(isColorWeakness, c, graph[nx][ny])) continue
visited[nx][ny] = true
queue.add(Move(nx, ny))
}
}
}
data class Move(val x: Int, val y: Int)
private fun check(isColorWeakness: Boolean, c1: Char, c2: Char): Boolean {
if (c1 == c2)
return true
if (isColorWeakness) {
if (c1 == 'R' && c2 == 'G')
return true
if (c1 == 'G' && c2 == 'R')
return true
}
return false
}
3차원 공간 bfs를 통해 거리 구하기
- 익은 토마토가 없을 경우
- 익어있지 않은 토마토가 있을 경우
- 이미 다 익어있을 경우 등을 생각해서 처리하기
import java.io.*
import java.util.*
import kotlin.system.exitProcess
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
var st = StringTokenizer(readLine())
val m = st.nextToken().toInt() // 가로
val n = st.nextToken().toInt() // 세로
val h = st.nextToken().toInt() // 높이
val graph = Array(h) { Array(n) { IntArray(m) {-1} } }
val tomato = Array(h) { Array(n) { IntArray(m) {-1} } }
var count = 0
var days = 0
val queue = ArrayDeque<Move>()
for (height in 0 until h) {
for (row in 0 until n) {
st = StringTokenizer(readLine())
for (col in 0 until m) {
val current = st.nextToken().toInt()
graph[height][row][col] = current
if (current == 1) {
queue.add(Move(height, row, col))
tomato[height][row][col] = 0 // 익은 토마
count++
}
if (current == -1) {
tomato[height][row][col] = -2 // 빈 공간
}
}
}
}
val bw = BufferedWriter(OutputStreamWriter(System.out))
if (count == 0) { // 익은 토마토가 하나도 없을 경우
bw.write("-1")
bw.close()
exitProcess(0)
}
val dx = arrayOf(1, -1, 0, 0, 0, 0) // 위 아래 왼쪽 오른쪽 앞 뒤
val dy = arrayOf(0, 0, -1, 1, 0, 0)
val dz = arrayOf(0, 0, 0, 0, 1, -1)
for (height in 0 until h) {
for (row in 0 until n) {
for (col in 0 until m) {
// bfs
while (queue.isNotEmpty()) {
val current = queue.remove()
for (i in 0 until 6) {
val nx = current.x + dx[i]
val ny = current.y + dy[i]
val nz = current.z + dz[i]
if (nx < 0 || nx >= n || ny < 0 || ny >= m || nz < 0 || nz >= h) continue
if (graph[nz][nx][ny] == -1 || tomato[nz][nx][ny] != -1) continue
tomato[nz][nx][ny] = tomato[current.z][current.x][current.y] + 1
queue.add(Move(nz, nx, ny))
days = tomato[current.z][current.x][current.y] + 1
}
}
}
}
}
for (height in 0 until h) {
for (row in 0 until n) {
for (col in 0 until m) {
if (tomato[height][row][col] == -1) { // 익지 않은 토마토가 있을 경우
bw.write("-1")
bw.close()
exitProcess(0)
}
}
}
}
bw.write("$days")
bw.close()
}
data class Move(val z: Int, val x: Int,val y: Int)
이동 가능한 칸이 좀 귀찮게 생겼다
x 가로 y 세로
2, -2 | 2, -1 | 2, 0 | 2, 1 | 2, 2 |
1, -2 | 1, -1 | 1, 0 | 1, 1 | 1, 2 |
0, -2 | 0, -1 | 0, 0 | 0, 1 | 0, 2 |
-1, -2 | -1, -1 | -1, 0 | -1, 1 | -1, 2 |
-2, -2 | -2, -1 | -2, 0 | -2, 1 | -2, 2 |
나이트가 이동할 수 있는 칸
(2, -1), (2, 1), (1, -2), (1, 2), (-1, -2), (-1, 2), (-2, -1), (-2, 1)
dx = arrayOf (2, 2, 1, 1, -1, -1, -2, -2)
dy = arrayOf (-1, 1, -2, 2, -2, 2, -1, 1)
나이트가 목표지점에 도달할 때까지 탐색을 진행한다
import java.io.*
import java.util.*
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val t = readLine().toInt()
val dx = arrayOf(2, 2, 1, 1, -1, -1, -2, -2)
val dy = arrayOf(-1, 1, -2, 2, -2, 2, -1, 1)
val bw = BufferedWriter(OutputStreamWriter(System.out))
repeat(t) {
val l = readLine().toInt() // 체스판 한변의 길이
val queue = ArrayDeque<Location>()
val dist = Array(l) { IntArray(l) { -1 } }
var st = StringTokenizer(readLine())
val current = Location(st.nextToken().toInt(), st.nextToken().toInt())
dist[current.x][current.y] = 0
queue.add(current)
st = StringTokenizer(readLine())
val destination = Location(st.nextToken().toInt(), st.nextToken().toInt())
// bfs
while (queue.isNotEmpty()) {
val location = queue.remove()
// 목표 지점 도달
if (location == destination) {
bw.write("${dist[location.x][location.y]}\n")
}
for (m in 0 until 8) {
val nx = location.x + dx[m]
val ny = location.y + dy[m]
if (nx < 0 || ny < 0 || nx >= l || ny >= l) continue
if (dist[nx][ny] != -1) continue
dist[nx][ny] = dist[location.x][location.y] + 1
queue.add(Location(nx, ny))
}
}
}
bw.close()
}
data class Location(val x: Int, val y: Int)
불 bfs -> 상근이 bfs
어떤 위치에 불이 도달하는 시간이 상근이가 도달하는 시간보다 적을 경우 상근이는 해당 위치를 통과할 수 없다
상근이는 주어진 공간을 벗어난 경우 탈출했다고 볼 수 있다
import java.io.*
import java.util.*
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val t = readLine().toInt()
val dx = arrayOf(1, -1, 0, 0)
val dy = arrayOf(0, 0, -1, 1)
val bw = BufferedWriter(OutputStreamWriter(System.out))
repeat(t) {
val st = StringTokenizer(readLine())
val w = st.nextToken().toInt()
val h = st.nextToken().toInt()
val map = Array(h) { CharArray(w)}
val fireQueue = ArrayDeque<Location>()
val fireDist = Array(h) { IntArray(w) { -1 } }
val sgQueue = ArrayDeque<Location>()
val sgDist = Array(h) { IntArray(w) { -1 } }
// 지도 만들기
for (i in 0 until h) {
val s = readLine()
s.forEachIndexed { j, c ->
map[i][j] = c
if (c == '*') {
fireQueue.add(Location(i, j))
fireDist[i][j] = 0
}
if (c == '@') {
sgQueue.add(Location(i, j))
sgDist[i][j] = 0
}
}
}
// 불 bfs
while (fireQueue.isNotEmpty()) {
val current = fireQueue.remove()
for (i in 0 until 4) {
val nx = current.x + dx[i]
val ny = current.y + dy[i]
if (nx in 0 until h && ny in 0 until w) {
if (!map[nx][ny].isWall() && fireDist[nx][ny] == -1) {
fireDist[nx][ny] = fireDist[current.x][current.y] + 1
fireQueue.add(Location(nx, ny))
}
}
}
}
// 상근 bfs
while (sgQueue.isNotEmpty()){
val current = sgQueue.remove()
for (i in 0 until 4) {
val nx = current.x + dx[i]
val ny = current.y + dy[i]
if (nx < 0 || nx >= h || ny < 0 || ny >= w) {
bw.write("${sgDist[current.x][current.y] + 1}\n")
return@repeat
}
if (map[nx][ny].isWall() || sgDist[nx][ny] != -1) continue
if (fireDist[nx][ny] != -1 && fireDist[nx][ny] <= sgDist[current.x][current.y] + 1) continue
sgDist[nx][ny] = sgDist[current.x][current.y] + 1
sgQueue.add(Location(nx, ny))
}
}
bw.write("IMPOSSIBLE\n")
}
bw.close()
}
data class Location(val x: Int, val y: Int)
private fun Char.isWall() = this == '#'
'알고리즘&자료구조' 카테고리의 다른 글
재귀 (0) | 2022.12.14 |
---|---|
BFS 응용문제 풀기 (0) | 2022.12.06 |
BFS (0) | 2022.11.29 |
스택의 활용 : 수식의 괄호쌍 (0) | 2022.11.25 |
덱 : Deque (1) | 2022.11.23 |