본문 바로가기

ALGORITHM/DFS, BFS

[Swift] 2234 성곽 (BFS)

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

 

2234번: 성곽

첫째 줄에 두 정수 N, M이 주어진다. 다음 M개의 줄에는 N개의 정수로 벽에 대한 정보가 주어진다. 벽에 대한 정보는 한 정수로 주어지는데, 서쪽에 벽이 있을 때는 1을, 북쪽에 벽이 있을 때는 2를,

www.acmicpc.net

 

생각

[ struct wall ]

wall은 벽에대한 정보보다는 그 위치의 대한 정보라서

- 위치 r, c

- 동서남북 벽의 유무

- 방의 번호 : 벽을 허물었을 때 현재 방의 넓이를 알 수 있도록

로 선언하였다.

 

c++ 로 풀 때는 << 로 비트로 풀었지만, Swift에서 비트는 아직 어색하고 잘 모르기 때문에

init 함수에서 직접 나눠주면서 벽의 유무를 설정해주었다.

 

[ BFS ]

그리고 방문하지 않은 곳이라면 bfs로 돌면서 방의 번호를 설정하고 방의 넓이를 구해서 저장해놓았다.

 

[ getLargeAreaWithRemoveWall ]

원래 BFS 하나 더 만들어서 구했다가 시간초과가 나서 (이 원인은 아니다)

삼중 for문으로 바꿔서 다음 위치가 다른 방 번호면 두개의 방 넓이를 더해주었다.

 

 

 

새벽에 문제가 잘풀릴 것 같아서 풀었다가 bfs를 오랜만에 풀어서 진짜 호되게~당했다..

혼자서 struct 만들고 어렵게 푼거같기도..

 

시간초과가 났었던 이유는, bfs 함수에서

visited 변수를 queue 에 넣을 때 true로 바꿔주지 않고

queue에서 뺐을 때 true로 바꿔주기 때문이었다.

 

 

import Foundation

// input: M, N
var input = readLine()!.split(separator: " ").map{ Int($0)! }
let N = input[0]
let M = input[1]

// 위치에 대한 정보
struct wall {
    var r: Int = 0
    var c: Int = 0
    var east: Bool = false
    var west: Bool = false
    var south: Bool = false
    var north: Bool = false
    var roomNum: Int = -1
    
    // 2로 나눠서 벽이 있는지 확인 후에 벽 설정
    init(_ r: Int, _ c: Int, _ info: Int) {
        self.r = r
        self.c = c
        
        var num = info, count = 0
        if info == 0 {
            return
        }
        while count < 4 {
            if num == 1 {
                setDirection(count, 1)
                break
            }
            setDirection(count, num % 2)
            num = num / 2
            count += 1
        }
    }
    
    mutating func setDirection(_ count: Int, _ val: Int) {
        let isWall = val == 1 ? true : false
        switch count {
        case 0: west = isWall
        case 1: north = isWall
        case 2: east = isWall
        case 3: south = isWall
        default: break
        }
    }
    
    // 벽이 있는지 확인
    func isWall(_ direction: Int) -> Bool {
        switch direction {
        case 0: return west
        case 1: return north
        case 2: return east
        case 3: return south
        default: break
        }
        return false
    }
}

// MARK: - 변수
// 성벽
var walls = [[wall]](Array(repeating: Array(repeating: wall(0, 0, 0), count: N), count: M))
// 탐색을 위한 visited 변수
var visited = [[Bool]](Array(repeating: Array(repeating: false, count: N), count: M))
// 방의 갯수, 넓은 방의 넓이, 벽 제거 후 넓은 방의 넓이
var roomCount = 0, largeArea = 0, largeAreaWithReomveWall = 0

// 방의 넓이 저장 roomCount로
var roomArea = [Int](Array(repeating: 0, count: N*M))

// west, north, east, south
let dr = [0, -1, 0, 1]
let dc = [-1, 0, 1, 0]


// input
for i in 0..<M {
    input = readLine()!.split(separator: " ").map{ Int($0)! }
    for j in 0..<N {
        walls[i][j] = wall(i, j, input[j])
    }
}

// MARK: - 함수
// 범위
func isIn(_ r: Int, _ c: Int) -> Bool {
    return 0<=r && r<M && 0<=c && c<N
}

// 탐색
func bfs(_ startR: Int, _ startC: Int) {
    var area = 0, nr = 0, nc = 0
    // queue라고 생각
    var queue = [wall]()
    
    queue.append(walls[startR][startC])
    visited[startR][startC] = true
    
    while !queue.isEmpty {
        let curWall = queue.first!
        walls[curWall.r][curWall.c].roomNum = roomCount
        area += 1
        queue.removeFirst()
        
        for i in 0..<4 {
            nr = curWall.r + dr[i]
            nc = curWall.c + dc[i]
            if isIn(nr, nc) && !visited[nr][nc] && !curWall.isWall(i) {
                visited[nr][nc] = true
                queue.append(walls[nr][nc])
            }
        }
    }
    roomArea[roomCount] = area
    largeArea = max(area, largeArea)
}

func getLargeAreaWithRemoveWall() {
    var nr = 0, nc = 0
    for i in 0..<M {
        for j in 0..<N {
            for k in 0..<3 {
                nr = walls[i][j].r + dr[k]
                nc = walls[i][j].c + dc[k]
                if isIn(nr, nc) && walls[i][j].roomNum != walls[nr][nc].roomNum {
                    largeAreaWithReomveWall = max(largeAreaWithReomveWall,
                                                  roomArea[walls[i][j].roomNum] +
                                                  roomArea[walls[nr][nc].roomNum])
                }
            }
        }
    }
}

// main
for i in 0..<M {
    for j in 0..<N {
        if !visited[i][j] {
            bfs(i, j)
            roomCount += 1
            
        }
    }
}

getLargeAreaWithRemoveWall()

print(roomCount)
print(largeArea)
print(largeAreaWithReomveWall)

개길다

'ALGORITHM > DFS, BFS' 카테고리의 다른 글

[Swift] Lv3. 여행경로 (dfs)  (0) 2022.04.03
[Java] 17406 배열 돌리기 4  (0) 2021.08.12
[c++] 타겟 넘버 (프로그래머스 - dfs)  (0) 2021.06.29
2580 스도쿠  (0) 2021.01.18
14889 스타트와 링크  (0) 2021.01.16