[BFS + 구현] 백준 2573번: 빙산

2022. 11. 14. 20:29·코테

https://www.acmicpc.net/problem/2573

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

난이도

골드 4

사용언어

swift

카테고리

BFS + 구현

풀이과정

첫 제출 Code

struct Queue<T> {
  var memory = [T]()
  var index = 0
  
  var isEmpty: Bool {
    memory.count < index + 1
  }
  
  mutating func inQueue(element: T) {
    memory.append(element)
  }
  
  mutating func deQueue() -> T {
    let v = memory[index]
    index += 1
    return v
  }
}

let nm = readLine()!.split(separator: " ").map { Int($0)! }
let n = nm[0]
let m = nm[1]

var map = [[Int]]()
var s = Array(repeating: Array(repeating: 0, count: m), count: n)
var visited = Array(repeating: Array(repeating: false, count: m), count: n)
var count = 0

for _ in 0..<n {
  let v = readLine()!.split(separator: " ").map { Int($0)! }
  map.append(v)
}

var q = Queue<(y: Int, x: Int)>()
let direction: [(y: Int, x: Int)] = [
  (0,-1),
  (0,1),
  (-1,0),
  (1,0)
]

func bfs(start: (y: Int, x: Int)) {
  q.inQueue(element: start)
  visited[start.y][start.x] = true
  count += 1
  while !q.isEmpty {
    let cp = q.deQueue()
    
    for i in 0..<direction.count {
      let np: (y: Int, x: Int) = (cp.y + direction[i].y, cp.x + direction[i].x)
      if map[np.y][np.x] == 0 {
        s[cp.y][cp.x] += 1
      }
      if (0..<n).contains(np.y) &&
          (0..<m).contains(np.x) &&
          !visited[np.y][np.x] &&
          map[np.y][np.x] != 0 {
        visited[np.y][np.x] = true
        q.inQueue(element: np)
      }
    }
  }
}

func next() {
  for y in 0..<n {
    for x in 0..<m {
      map[y][x] -= s[y][x]
      if map[y][x] < 0 {
        map[y][x] = 0
      }
    }
  }
  s = Array(repeating: Array(repeating: 0, count: m), count: n)
  visited = Array(repeating: Array(repeating: false, count: m), count: n)
  count = 0
}
var result = 0
while true {
  for y in 0..<n {
    for x in 0..<m {
      if map[y][x] != 0 &&
          !visited[y][x] {
        bfs(start: (y, x))
      }
    }
  }
  if count == 1 {
    next()
    result += 1
  } else {
    print(count == 0 ? 0 : result)
    break
  }
}

첫 제출에서 통과가 되었긴 했지만, 시간이 884ms가 나왔다. 어떻게 하면 개선할 수 있을가 생각하며, 블로그를 찾아보던 중

https://velog.io/@aurora_97/%EB%B0%B1%EC%A4%80-2573%EB%B2%88-%EB%B9%99%EC%82%B0-Swift

 

백준 2573번: 빙산 - Swift

https://www.acmicpc.net/problem/2573 난이도 골드4 🥇 알고리즘 분류: 구현, bfs 🧐 문제접근 요구한 것대로 정확히 구현하면 되는 문제입니다. 얼음이 존재하는 부분만 ices 배열로 따로 관리해 줍니다.

velog.io

위 블로그 글을 통해서 코드의 문제점을 알 수 있었다. 문제는 모든 좌표를 탐색했기 때문이다. 

위와 같이 빙산이 존재하는 위치를 배열로 따로 관리하여,

사진과 같이 탐색해 주도록 수정하였더니 188ms로 개선할 수 있었다.

최종 코드

struct Queue<T> {
  var memory = [T]()
  var index = 0
  
  var isEmpty: Bool {
    memory.count < index + 1
  }
  
  mutating func inQueue(element: T) {
    memory.append(element)
  }
  
  mutating func deQueue() -> T {
    let v = memory[index]
    index += 1
    return v
  }
}

let nm = readLine()!.split(separator: " ").map { Int($0)! }
let n = nm[0]
let m = nm[1]

var map = [[Int]]()
var icePs = [(y: Int, x: Int)]()

for y in 0..<n {
  let v = readLine()!.split(separator: " ").map { Int($0)! }
  map.append(v)
  for x in 0..<m {
    if v[x] != 0 {
      icePs.append((y,x))
    }
  }
}

var q = Queue<(y: Int, x: Int)>()
let direction: [(y: Int, x: Int)] = [
  (0,-1),
  (0,1),
  (-1,0),
  (1,0)
]

func bfs(start: (y: Int, x: Int), visited: inout [[Bool]], removeArr: inout [[Int]]) {
  q.inQueue(element: start)
  visited[start.y][start.x] = true
  while !q.isEmpty {
    let cp = q.deQueue()
    
    for i in 0..<direction.count {
      let np: (y: Int, x: Int) = (cp.y + direction[i].y, cp.x + direction[i].x)
      
      if (0..<n).contains(np.y) &&
          (0..<m).contains(np.x) {
        
        if map[np.y][np.x] == 0 {
          removeArr[cp.y][cp.x] += 1
        } else if !visited[np.y][np.x] &&
                    map[np.y][np.x] != 0 {
          visited[np.y][np.x] = true
          q.inQueue(element: np)
        }
        
      }
    }
  }
}

func nextYear(removeArr: inout [[Int]]) {
  var temp = [(y: Int, x: Int)]()
  for (y, x) in icePs {
    if map[y][x] - removeArr[y][x] > 0 {
      map[y][x] -= removeArr[y][x]
      temp.append((y, x))
    } else {
      map[y][x] = 0
    }
  }
  icePs = temp
  year += 1
}

var year = 0
while true {
  var removeIceCounts = Array(repeating: Array(repeating: 0, count: m), count: n)
  var visited = Array(repeating: Array(repeating: false, count: m), count: n)
  var count = 0
  
  for (y, x) in icePs {
    if !visited[y][x] {
      bfs(start: (y, x), visited: &visited, removeArr: &removeIceCounts)
      count += 1
    }
  }
  if count == 1 {
    nextYear(removeArr: &removeIceCounts)
  } else {
    print(count == 0 ? 0 : year)
    break
  }
}

'코테' 카테고리의 다른 글

[DFS] 백준 9466번: 텀 프로젝트(Swift)  (0) 2022.12.03
[DFS] 백준 1068번: 트리(Swift)  (0) 2022.11.18
[DFS] 백준 1707번: 이분 그래프(Swift)  (0) 2022.11.11
[DFS + DP] 백준 1520번: 내리막길(Swift)  (0) 2022.11.11
[DFS] 백준 2644번: 촌수계산(Swift)  (0) 2022.11.09
'코테' 카테고리의 다른 글
  • [DFS] 백준 9466번: 텀 프로젝트(Swift)
  • [DFS] 백준 1068번: 트리(Swift)
  • [DFS] 백준 1707번: 이분 그래프(Swift)
  • [DFS + DP] 백준 1520번: 내리막길(Swift)
Esiwon
Esiwon
iOS 개발 블로그
  • Esiwon
    시원한 코드 기록
    Esiwon
  • 전체
    오늘
    어제
    • 분류 전체보기 (70)
      • iOS&Swift (24)
      • git & github (1)
      • 코테 (41)
      • 네부캠 회고 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

  • 인기 글

  • 태그

    Property wrapper
    그리디
    탐색
    네부캠
    실버
    Combine
    비동기
    PhotoKit
    백준
    코테
    Swift
    photoUI
    회고
    챌린지
    이분탐색
    dfs
    노드
    코딩테스트
    BFS
    다이나믹 프로그래밍
    동시성
    Race Condition
    완전탐색
    구현
    ios
    GCD
    알고리즘
    photos
    재귀
    브루트포스 알고리즘
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Esiwon
[BFS + 구현] 백준 2573번: 빙산
상단으로

티스토리툴바