privatefunsolve() { // 색상 종류 카운팅 및 초기화 calcColorCount()
// above[i][j] = 특정 색상값 i에 올라올 수 있는 색상값이 있느냐 없느냐를 구분 above = Array(count) { BooleanArray(count) { false } }
// 색상별 카드 범위 계산 calcCardArea() // 계산 불가능한 경우의 예외 처리 if (result == "-1") { println(result) return }
topologicalSort()
println("$result") }
privatefunprintGraph(msg: String?) { msg?.let { println("=== $it") } for (i in0 until N) { for (j in0 until M) { print("${grid[i][j]} ") } println() } }
privatefuncalcColorCount() { var index = 0 for (i in0 until N) { for (j in0 until M) { var ch = grid[i][j] // 공백이 아니고, 아직 계산 안한 색상값이라면 추가 if (ch != EMPTY && !colorMap.containsKey(ch)) { colorId[index] = ch colorMap[ch] = index index++ } } } count = index }
privatefuncalcCardArea() { // 계산한 총 색상의 종류만큼 반복 for (i in0 until count) { var minX = N - 1 var maxX = -1 var minY = M - 1 var maxY = -1
// 특정 색상값이 그리드에서 차지하고 있는 영역 계산 for (x in0 until N) { for (y in0 until M) { if (grid[x][y] == colorId[i]) { minX = min(minX, x) maxX = max(maxX, x) minY = min(minY, y) maxY = max(maxY, y) } } }
// 계산해낸 그리드의 영역내에 겹쳐진 색상값을 찾는다. for (x in minX .. maxX) { for (y in minY .. maxY) { // 계산하는 영역이 공백이면 가능한 순서가 존재하지않음 if (grid[x][y] == EMPTY) { result = "-1" return } // 다른 색상값이 존재하면 현재 계산중인 색상의 카드 위에 다른 카드가 존재할 수 있음 if (grid[x][y] != colorId[i]) { var color = grid[x][y] if (colorMap.containsKey(color)) { above[i][colorMap[color]!!] = true } } } } } }
privatefuntopologicalSort() { var removed = BooleanArray(count) { false } for (i in0 until count) { var pick = 'z' + 1// 최대값 123 var target = -1// 최솟값
// 색상만큼 순회 for (j in0 until count) { if (removed[j]) { continue } // 밑에 깔려있다면 result에 추가한다. var isBelow = true // 제거 되지않은 색상이면서, 위에 있는 카드가 아닌 경우 for (k in0 until count) { isBelow = isBelow and (removed[k] || !above[k][j]) } if (isBelow) { if (pick > colorId[j]) { target = j pick = colorId[j] } if (j < target && pick == colorId[j]) { target = j } } }
// 계산 불가능한 경우 if (target == -1) { result = "-1" return } result += pick // 계산한 색상은 제외 removed[target] = true } }
Point of Thinking
주어진 grid에서 유니크한 색상값들을 먼저 카운팅해야 한다.
결국 색상값의 종류들을 어떻게 나열할지 결정하는 문제이기 때문
색상값의 범위는 a-z, A-Z, 0-9 이므로 122칸의 배열의 인덱스로 표현할 수 있다.
카드는 직사각형 형태이므로, 해당 카드의 고윳값의 좌상단, 좌하단, 우상단, 우하단의 좌표값을 통해 영역을 추출할 수 있다.
주어진 영역내에 다른 색상값이 존재한다면, 계산중인 카드 위에 또 다른 카드가 올라와있다고 볼 수 있다.
이는 기존 카드를 완전히 덮어쓰는 카드는 없다는 문제의 조건에서 추측할 수 있다. (애초에 이러면 문제가 성립이 안되긴 하지만)
색상 종류와 카드 영역 계산을 통한 덮어쓰기 유무까지 추출했다면 이를 바탕으로 위상 정렬을 수행한다.
위상 정렬 && 계산한 색상을 배제하기 위해 제거된 색상 관리를 위한 배열을 조건에 추가한 뒤, 올라올 수 있는 카듸 조건에 부합하면 결과값에 추가하면 된다.
문제가 매우 복잡해서 solve() 함수안에서 다 작성하기가 힘들었기때문에 문제를 분할한 뒤, 각각 메서드로 분리하여 풀었다.