
주변에 좋아하는 학생이 많도록 자리를 배치하는 문제
문제 자체는 이해가 쉬웠다!
그대로 구현하는 게 시간이 걸릴 뿐...🤯
사실 며칠 전에 풀다가 만 코드가 있었는데,
다시 보니까 무슨 소린지 전혀 모르겠어서 처음부터 다시 짰다 ㅋㅋ
정확하게 뭘 짜야 하는지 주석부터 달고 시작했더니 가닥이 쉽게 잡히는 것 같다
let n = Int(readLine()!)! var seats = Array(repeating: Array(repeating: 0, count: n), count: n) // 전체 좌석 만들기
우선 전체 좌석을 만들고 초기화해주었다
그리고 n * n 만큼 for문을 돌면서 한 줄씩 읽었다
한 명의 번호와 그 학생이 좋아하는 학생 번호들이 나열되기 때문에
한 줄을 읽을 때마다 실행해야할 것들이 많았음!
// 학생 번호와 좋아하는 학생 번호 받아오기 let numbers = readLine()!.split(separator: " ").map({Int($0)!}) // 학생들을 배치할 수 있는 칸 저장 var answer: [[Int]] = [] for i in 0...n - 1 { for j in 0...n - 1 { if seats[i][j] == 0 { answer.append([i, j]) } } }
배치가 가능한 칸을 초기화해줌
이 answer 배열을 이제 조건에 맞춰 하나씩 줄여갈 것이다
크게 세 가지 조건이 있었다
// 자리 배치하기 // 1. 비어있는 칸 중에 인접 칸에 좋아하는 학생이 많은 칸 찾기 answer = checkLike() // 2. 남은 칸이 여러 개라면, 인접 칸에 비어있는 칸이 많은 칸 찾기 if answer.count > 1 { answer = checkEmpty() } // 3. 남은 칸이 여러 개라면, 행의 번호가 작은 칸, 또 여러 개라면 열의 번호가 작은 칸 찾기 if answer.count > 1 { answer = checkNum() } // 마지막 남은 좌석에 학생 배치! seats[answer[0][0]][answer[0][1]] = student
이렇게 주석과 함수로 큰 틀을 잡아 놓고 시작을 해보았다
checkLike, checkEmpty, checkNum 은 answer 배열과 같은 [[Int]]를 return 할 것이라고 염두에 두고 시작
let dr = [0, 0, -1, 1] let dc = [-1, 1, 0, 0] // 1. 비어있는 칸 중에 인접 칸에 좋아하는 학생이 많은 칸 찾기 func checkLike(_ student: Int, likes: [Int], seatsLeft: [[Int]]) -> [[Int]] { var likeCountList: [Int] = Array(repeating: 0, count: seatsLeft.count) // 칸마다 인접 좋아하는 학생 수 세어 넣기 위한 초기화 var maxLike = 0 // 남은 좌석들 중 인접 네 칸에 좋아하는 학생이 있는 곳 세기 for i in 0...seatsLeft.count - 1 { let seat = seatsLeft[i] var likeCount = 0 // 좋아하는 학생 수 세기 리셋 let r = seat[0] let c = seat[1] for i in 0...3 { // 상하좌우 돌아가며 확인 if r + dr[i] >= 0 && c + dc[i] >= 0 && r + dr[i] < n && c + dc[i] < n { if likes.contains(seats[r + dr[i]][c + dc[i]]) { likeCount += 1 } } } maxLike = max(maxLike, likeCount) // 가장 많은 칸을 위해 max값 업데이트 likeCountList[i] = likeCount } var answer: [[Int]] = [] for i in 0...likeCountList.count - 1 { if likeCountList[i] == maxLike { answer.append(seatsLeft[i]) // 가장 많이 인접한 칸을 모두 append } } return answer }
우선 인접 상하좌우를 체크하기 위해 dr, dc를 만들었다
하나하나의 칸마다 인접한 좋아하는 학생 수를 적기 위해 likeCountList를 초기화했고,
근처에 좋아하는 학생이 가장 많은 곳은 몇 명이나 있을지를 확인하기 위해 maxLike를 정의했다
자리를 돌아가면서 하나씩 확인하고 가능한 자리를 answer에 append후 return 하는 것!!
// 2. 남은 칸이 여러 개라면, 인접 칸에 비어있는 칸이 많은 칸 찾기 func checkEmpty(_ student: Int, seatsLeft: [[Int]]) -> [[Int]] { var emptyCountList: [Int] = Array(repeating: 0, count: seatsLeft.count) // 칸마다 인접 빈 칸 세어 넣기 위한 초기화 var maxEmpty = 0 // 남은 좌석들 중 인접 네 칸에 빈 칸이 있는 곳 세기 for i in 0...seatsLeft.count - 1 { let seat = seatsLeft[i] var emptyCount = 0 // 빈 칸 세기 리셋 let r = seat[0] let c = seat[1] for i in 0...3 { if r + dr[i] >= 0 && c + dc[i] >= 0 && r + dr[i] < n && c + dc[i] < n { if seats[r + dr[i]][c + dc[i]] == 0 { emptyCount += 1 } } } maxEmpty = max(maxEmpty, emptyCount) emptyCountList[i] = emptyCount } var answer: [[Int]] = [] for i in 0...emptyCountList.count - 1 { if emptyCountList[i] == maxEmpty { answer.append(seatsLeft[i]) } } return answer }
2번 함수도 위와 비슷한 방식으로 했다.
위와 겹치는 코드가 많아 잘하면 코드를 더 줄일 수도 있을 것 같은데,
더 헷갈릴 것 같아서 우선은 따로 만들었음!
이렇게 하나씩 하면 앉을만한 좌석이 하나씩 사라지고,
마지막으로 남는 좌석들은 행, 열 순서가 그대로 반영되어 저장되기 때문에
가장 앞에 있는 녀석으로 학생을 배치하면 된다
seats[answer[0][0]][answer[0][1]] = student
마지막으로 만족도 조사 함수는 1번 함수와 비슷하게 하나씩 돌면서
근처에 좋아하는 학생이 몇 명 있는지를 모두 체크하고 totalScore에 반영했다
// 만족도 조사 func review() -> Int { var totalScore = 0 for i in 0...n - 1 { for j in 0...n - 1 { var likeCount = 0 for k in 0...3 { if i + dr[k] >= 0 && j + dc[k] >= 0 && i + dr[k] < n && j + dc[k] < n { let targetNum = seats[i + dr[k]][j + dc[k]] if likeArr[seats[i][j]]!.contains(targetNum) { // 인접한 칸에 좋아하는 학생이 있는지 확인 likeCount += 1 } } } if likeCount != 0 { totalScore += Int(NSDecimalNumber(decimal: pow(10, likeCount - 1))) } } } return totalScore }
여기서 pow 함수는 제곱을 구하는 함수인데, decimal이라서 Int로 바꿔주는 작업을 해야 함!
생각보다 쉬웠지만 그만큼 시간도 더 걸렸던 문제..!
구현 문제는 처음에 제대로 이해하고 큰 줄기를 잡아가며 풀어야 잘 풀리는 것 같다
전체 코드
import Foundation let n = Int(readLine()!)! var seats = Array(repeating: Array(repeating: 0, count: n), count: n) // 전체 좌석 만들기 var likeArr: [Int: [Int]] = [:] // 만족도 조사를 위헤 좋아하는 학생 리스트 저장해두기 let dr = [0, 0, -1, 1] let dc = [-1, 1, 0, 0] for _ in 0...n * n - 1 { // 학생 번호와 좋아하는 학생 번호 받아오기 let numbers = readLine()!.split(separator: " ").map({Int($0)!}) let student = Int(exactly: numbers[0])! let likes = numbers[1...4].map({Int(exactly: $0)!}) likeArr[student] = likes // 학생들을 배치할 수 있는 칸 저장 var answer: [[Int]] = [] for i in 0...n - 1 { for j in 0...n - 1 { if seats[i][j] == 0 { answer.append([i, j]) } } } // 자리 배치하기 // 1. 비어있는 칸 중에 인접 칸에 좋아하는 학생이 많은 칸 찾기 answer = checkLike(student, likes: likes, seatsLeft: answer) // 2. 남은 칸이 여러 개라면, 인접 칸에 비어있는 칸이 많은 칸 찾기 if answer.count > 1 { answer = checkEmpty(student, seatsLeft: answer) } // 3. 남은 칸이 여러 개라면, 행의 번호가 작은 칸, 또 여러 개라면 열의 번호가 작은 칸 찾기 // 자동으로 정렬되므로 따로 함수가 필요 없음 // 배치할 수 있는 칸 중 맨 앞(작은 행, 작은 열)에 학생 배치하기 seats[answer[0][0]][answer[0][1]] = student } // 1. 비어있는 칸 중에 인접 칸에 좋아하는 학생이 많은 칸 찾기 func checkLike(_ student: Int, likes: [Int], seatsLeft: [[Int]]) -> [[Int]] { var likeCountList: [Int] = Array(repeating: 0, count: seatsLeft.count) // 칸마다 인접 좋아하는 학생 수 세어 넣기 위한 초기화 var maxLike = 0 // 남은 좌석들 중 인접 네 칸에 좋아하는 학생이 있는 곳 세기 for i in 0...seatsLeft.count - 1 { let seat = seatsLeft[i] var likeCount = 0 // 좋아하는 학생 수 세기 리셋 let r = seat[0] let c = seat[1] for i in 0...3 { // 상하좌우 돌아가며 확인 if r + dr[i] >= 0 && c + dc[i] >= 0 && r + dr[i] < n && c + dc[i] < n { if likes.contains(seats[r + dr[i]][c + dc[i]]) { likeCount += 1 } } } maxLike = max(maxLike, likeCount) // 가장 많은 칸을 위해 max값 업데이트 likeCountList[i] = likeCount } var answer: [[Int]] = [] for i in 0...likeCountList.count - 1 { if likeCountList[i] == maxLike { answer.append(seatsLeft[i]) // 가장 많이 인접한 칸을 모두 append } } return answer } // 2. 남은 칸이 여러 개라면, 인접 칸에 비어있는 칸이 많은 칸 찾기 func checkEmpty(_ student: Int, seatsLeft: [[Int]]) -> [[Int]] { var emptyCountList: [Int] = Array(repeating: 0, count: seatsLeft.count) // 칸마다 인접 빈 칸 세어 넣기 위한 초기화 var maxEmpty = 0 // 남은 좌석들 중 인접 네 칸에 빈 칸이 있는 곳 세기 for i in 0...seatsLeft.count - 1 { let seat = seatsLeft[i] var emptyCount = 0 // 빈 칸 세기 리셋 let r = seat[0] let c = seat[1] for i in 0...3 { if r + dr[i] >= 0 && c + dc[i] >= 0 && r + dr[i] < n && c + dc[i] < n { if seats[r + dr[i]][c + dc[i]] == 0 { emptyCount += 1 } } } maxEmpty = max(maxEmpty, emptyCount) emptyCountList[i] = emptyCount } var answer: [[Int]] = [] for i in 0...emptyCountList.count - 1 { if emptyCountList[i] == maxEmpty { answer.append(seatsLeft[i]) } } return answer } // 만족도 조사 func review() -> Int { var totalScore = 0 for i in 0...n - 1 { for j in 0...n - 1 { var likeCount = 0 for k in 0...3 { if i + dr[k] >= 0 && j + dc[k] >= 0 && i + dr[k] < n && j + dc[k] < n { let targetNum = seats[i + dr[k]][j + dc[k]] if likeArr[seats[i][j]]!.contains(targetNum) { // 인접한 칸에 좋아하는 학생이 있는지 확인 likeCount += 1 } } } if likeCount != 0 { totalScore += Int(NSDecimalNumber(decimal: pow(10, likeCount - 1))) } } } return totalScore } print(review())
'공부하자! > 알고리즘' 카테고리의 다른 글
백준 | 9095 1, 2, 3 더하기 Swift - DP (0) | 2023.07.18 |
---|---|
LeetCode | 46. Permutations (Medium) - Swift (0) | 2023.07.14 |
백준 1913 달팽이 Swift - 구현 (0) | 2023.05.23 |
백준 20546 기적의 매매법 Swift - 구현 (0) | 2023.05.23 |
백준 20053 최소, 최대 2 Swift - 구현 (0) | 2023.05.13 |