(전공복습) 데이터과학 4. 시각화
차례
두 문제가 입출력, 제한 등 모든 면에서 완벽하게 같은 문제다.
따라서 같이 서술한다.
3*3 작은 마방진을 채우는 문제.
그냥 경우의 수를 생각해서 쉽게 풀 수 있다.
일단, 빈 칸이 최대 3개인 경우 마방진의 합을 알 수 없는 경우는 오직 빈칸 3개가 대각선으로 위치하는 두 가지 경우밖에 없다.
그 외의 경우 가로든 세로든 대각선이든 최소한 하나의 줄이 빈칸 없이 완성되므로 마방진의 합을 알 수 있게 된다.
마방진의 합을 아는 경우 문제는 매우 쉽다.
그냥 빈칸이 하나인 줄을 찾은 다음에, 그 줄의 빈칸을 채우면 되기 때문이다.
어차피 빈칸이 최대 3개이기 때문에, 언제든 적어도 하나의 줄이 하나의 빈칸만을 가진다.
마방진의 합을 모르는 경우, 간단한 방정식을 풀 필요가 있다.
이때, 대각선의 합과 1행의 합이 같다는 점을 이용할 것이다.
세 빈칸의 값을 각각 \(a\), \(b\), \(c\)라고 하자.
그리고 2, 3행의 빈칸이 아니면서 1행의 빈칸과 같은 열이 아닌 칸의 값을 각각 \(m\), \(n\)이라고 하자.
그렇다면 \(a + b + c = a + (a + b + c - b - m) + (a + b + c - c - n)\)이라 할 수 있다.
이 식을 정리하면 \(a = \frac {(m + n)} {2}\)임을 알 수 있다.
이제 빈칸 하나의 값을 알았으므로 빈칸이 2개인, 마방진의 합을 아는 문제가 되니 풀 수 있게 된다.
#!python
# n번째 빈칸에 val을 채우는 함수
def solve(n, val):
# 빈칸의 좌표를 가져온다
i, j = blanks[0][n], blanks[1][n]
# 보드에 값을 채우고 합을 저장하고 있는 sums 리스트를 갱신한다
board[i][j] = val
sums[0][i] += val
sums[1][j] += val
# 채워진 빈칸을 blanks에서 삭제한다
del blanks[0][n]
del blanks[1][n]
# board: 마방진
# sums[0][i]: i번째 행의 합
# sums[1][i]: i번째 열의 합
# blanks[0][i]: i번째 빈칸의 행 좌표
# blanks[1][i]: i번째 빈칸의 열 좌표
board = [list(map(int, input().split())) for _ in range(3)]
sums = [[0 for _ in range(3)] for _ in range(2)]
blanks = [[], []]
# 마방진을 순회하면서 sums와 blanks 리스트를 채운다
for i, line in enumerate(board):
for j, e in enumerate(line):
sums[0][i] += e
sums[1][j] += e
if not e:
blanks[0].append(i)
blanks[1].append(j)
# 빈칸이 대각선으로 3개 있는 경우
# 이 경우 바로 합을 알 수 없으므로 방정식을 통해 알아내야 한다
# 각 빈칸을 a, b, c라고 하고 2행, 3행의 빈칸이 아니면서 1행의 빈칸과 같은 열이 아닌 칸을 각각 m, n이라고 할 때
# 대각선의 합과 1행의 합은 같아야 하므로 a + b + c = a + (a + c - m) + (a + b - n)
# 0 = a - n + a - m
# 0 = 2a - m - n
# a = (m + n) // 2
if blanks in ([[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [2, 1, 0]]):
# 상술한 방정식으로 a, 즉 첫 번째 빈칸의 값을 구한다
# 빈칸 하나를 구했으므로 합도 계산할 수 있다
add = (board[2][1] + board[1][blanks[1][2]]) // 2
ans = sums[0][0] + add
# q는 남은 빈칸 개수
q = 2
# 0번째 빈칸에 구한 값을 채워넣는다
solve(0, add)
# 그 외의 경우 항상 적어도 하나의 줄을 통해 전체 합을 구할 수 있다
# 범위가 자연수이므로 마방진에서 합이 가장 큰 줄이 무조건 그 마방진의 합이 된다
else:
# sum[0]은 행, sum[1]은 열, 그 뒤의 리스트가 대각선
ans = max(sums[0] + sums[1] + [board[0][0] + board[1][1] + board[2][2], board[0][2] + board[1][1] + board[2][0]])
# q는 남은 빈칸 개수
q = len(blanks[0])
# 남은 빈칸을 전부 채울 때까지 반복
while q:
# 각 빈칸에 대해
for i in range(q):
# 남은 빈칸이 하나인 줄부터 해결
if 1 not in (blanks[0].count(blanks[0][i]), blanks[1].count(blanks[1][i])):
continue
# 행의 빈칸이 자신 혼자인 경우
if blanks[0].count(blanks[0][i]) == 1:
t = 0
# 열의 빈칸이 자신 혼자인 경우
else:
t = 1
# 해당 빈칸에 전체 합에서 그 빈칸이 속한 행/열의 합을 뺀 값을 채워넣는다
solve(i, ans - sums[t][blanks[t][i]])
q -= 1
break
for i in range(3):
print(*board[i])
문제 링크 문제 링크
개요 선형적인 자료구조에서는 값에 접근하는 데에 \(O(1)\)이면 충분하지만, 대신 부분합을 구하는 데에는 \(O(N)\)이 필요하다. 그렇다면 이 자료구조를 이진 트리로 구성하면 어떨까? 값에 접근하는 데에 걸리는 시간이 \(O(\lg N)\)으로 늘어나지만 대신 부분합을 구하...
개요 다익스트라 알고리즘과 함께 Single Sourse Shortest Path(SSSP) 문제를 푸는 알고리즘이다. 즉, 한 노드에서 다른 모든 노드로 가는 최단 경로를 구하는 알고리즘이다. 다익스트라 알고리즘보다 느리지만, 음수 가중치 간선이 있어도 작동하며, 음수 가중치 사...
개요 다익스트라 알고리즘은 Single Sourse Shortest Path(SSSP) 문제를 푸는 알고리즘 중 하나이다. 즉, 한 노드에서 다른 모든 노드로 가는 최단 경로를 구하는 알고리즘이다. 단, 다익스트라 알고리즘은 음수 가중치 엣지를 허용하지 않는다. 이 경우에는 벨만-...