테케 다 맞았는데 0%에서 틀렸습니다!가 나오는 문제
2차원 배열로 쌈싸먹는 완벽한 구현문제다
배열 돌려 배열 내려놔 배열 다시 돌려....
- 블록 그룹 찾기
- 일반 블록 최소 1개
- 검은 블록 포함 x
- 무지개 블록의 개수는 상관 x
- 블록의 조건
- 최소 2개 이상
- 일반 블록의 색은 모두 동일해야 함
- 기준 블록 : 행과 열이 가장 작은 블록(가장 왼쪽 위에 있는 블록)
- 크기가 가장 큰 블록 찾기
- 길이가 가장 긴 블록
- (길이가 같다면) 무지개 블록 개수가 큰 것
- (무지개 블록 개수가 같다면) 기준 블록의 행이 가장 큰 것
- (기준 블록 행도 같다면) 기준 블록 열이 가장 큰 것
- 중력 작용
- 검은색 블록(-1)은 중력의 영향을 받지 않는다
기본적으로 문제에서 알아낼 수 있는 부분은 이렇다.
위 2가지 때문에 0퍼에서 터지는 경우가 많은 거 같고 나는 아래에 있는 중복 부분은 처음부터 고려했는데 무지개 블록이 기준이 되는 경우는 고려를 못했었다.
일반적인 bfs 그래프 탐색 방식으로 찾았다.
def bfs(i, j, v, cnt):
v[i][j], start = cnt, block[i][j]
q = [(i, j)]
new_blocks, rbw = [(i, j)], []
while q:
r, c = q.pop(0)
for k in range(4):
nr, nc = r+dr[k], c+dc[k]
if -1<nr<N and -1<nc<N and block[nr][nc]>=0:
if block[nr][nc] == 0 and v[nr][nc] != cnt:
v[nr][nc] = cnt
q.append((nr, nc))
rbw.append((nr, nc))
elif block[nr][nc] == start and v[nr][nc] == 0:
v[nr][nc] = cnt
q.append((nr, nc))
new_blocks.append((nr, nc))
new_blocks, rbw = sorted(new_blocks), sorted(rbw)
return new_blocks + rbw, len(rbw)
def find_blockgroup():
v = [[0]*N for _ in range(N)]
blocks, max_rbw = [(-1, -1)], 0
cnt = 0
for i in range(N):
for j in range(N):
if block[i][j]>0 and not v[i][j]:
cnt += 1
new_blocks, len_rbw = bfs(i, j, v, cnt)
if len(new_blocks) < 2 or len(blocks) > len(new_blocks):
continue
elif len(blocks) == len(new_blocks) and max_rbw > len_rbw:
continue
elif max_rbw == len_rbw and blocks[0][0] > new_blocks[0][0]:
continue
elif blocks[0][0] == new_blocks[0][0] and blocks[0][1] > new_blocks[0][1]:
continue
blocks, max_rbw = new_blocks[:], len_rbw
return blocks
한 번에 해결할 수 있는 깔끔한 코드를 찾아서 리팩토링했다 -> 코드
def bfs(si, sj, v, cnt):
v[si][sj], t = cnt, block[si][sj]
Q, idx, rbw = [(si, sj)], 0, 0
while idx < len(Q):
i, j = Q[idx]
for ni, nj in (i-1, j), (i+1, j), (i, j-1), (i, j+1):
if -1<ni<N and -1<nj<N and (b:=block[ni][nj])>=0:
if b == 0 and v[ni][nj] != cnt:
v[ni][nj] = cnt
Q.append((ni, nj))
rbw += 1
elif b==t and v[ni][nj] == 0:
v[ni][nj] = cnt
Q.append((ni, nj))
idx += 1
return [len(Q), rbw, si, sj, Q]
def find_blockgroup():
v = [[0]*N for _ in range(N)]
max_blocks = [0, 0, -1, -1, []]
cnt = 0
for i in range(N):
for j in range(N):
if block[i][j]>0 and not v[i][j]:
cnt += 1
max_blocks = max(max_blocks, bfs(i, j, v, cnt))
return max_blocks[-1]
기본적으로 0열부터 N-1열까지 비교하는 방식이고, 가장 아래에 있는 행에서부터 위로 올라오는 방식으로 구현.
# 중력 작용
def gravity(arr):
for j in range(N):
bot = i = N-1
while -1<i:
t = arr[i][j]
if t == -1:
bot = i-1
elif t>=0:
if bot > i:
arr[bot][j] = t
arr[i][j] = -2
bot -= 1
i -= 1
return arr
# 60ms
# 반시계 방향의 회전
def rotate(arr):
return list(map(list, zip(*arr)))[::-1]
# bfs로 블럭 탐색
def bfs(i, j, v, cnt):
v[i][j], start = cnt, block[i][j]
q = [(i, j)]
new_blocks, rbw = [(i, j)], []
while q:
r, c = q.pop(0)
for k in range(4):
nr, nc = r+dr[k], c+dc[k]
if -1<nr<N and -1<nc<N and block[nr][nc]>=0:
if block[nr][nc] == 0 and v[nr][nc] != cnt:
v[nr][nc] = cnt
q.append((nr, nc))
rbw.append((nr, nc))
elif block[nr][nc] == start and v[nr][nc] == 0:
v[nr][nc] = cnt
q.append((nr, nc))
new_blocks.append((nr, nc))
new_blocks, rbw = sorted(new_blocks), sorted(rbw)
return new_blocks + rbw, len(rbw)
# 블럭의 집합 찾기
def find_blockgroup():
v = [[0]*N for _ in range(N)]
blocks, max_rbw = [(-1, -1)], 0
cnt = 0
for i in range(N):
for j in range(N):
if block[i][j]>0 and not v[i][j]:
cnt += 1
new_blocks, len_rbw = bfs(i, j, v, cnt)
if len(new_blocks) < 2 or len(blocks) > len(new_blocks):
continue
elif len(blocks) == len(new_blocks) and max_rbw > len_rbw:
continue
elif max_rbw == len_rbw and blocks[0][0] > new_blocks[0][0]:
continue
elif blocks[0][0] == new_blocks[0][0] and blocks[0][1] > new_blocks[0][1]:
continue
blocks, max_rbw = new_blocks[:], len_rbw
return blocks
# 그룹 제거 + 점수 합산
def remove(blocks):
global res
res += len(blocks) ** 2
for br, bc in blocks:
block[br][bc] = -2
# 중력 작용
def gravity(arr):
for j in range(N):
bot = i = N-1
while -1<i:
t = arr[i][j]
if t == -1:
bot = i-1
elif t>=0:
if bot > i:
arr[bot][j] = t
arr[i][j] = -2
bot -= 1
i -= 1
return arr
def autoplay():
global block
while 1:
blocks = find_blockgroup()
if len(blocks) == 1:
return
remove(blocks)
gravity(block)
block = gravity(rotate(block))
N, M = map(int, input().split())
block = [list(map(int, input().split())) for _ in range(N)]
dr, dc = (0, 1, 0, -1), (-1, 0, 1, 0)
res = 0
autoplay()
print(res)
# 60ms
def rotate(arr):
return list(map(list, zip(*arr)))[::-1]
def bfs(si, sj, v, cnt):
v[si][sj], t = cnt, block[si][sj]
Q, idx, rbw = [(si, sj)], 0, 0
while idx < len(Q):
i, j = Q[idx]
for ni, nj in (i-1, j), (i+1, j), (i, j-1), (i, j+1):
if -1<ni<N and -1<nj<N and (b:=block[ni][nj])>=0:
if b == 0 and v[ni][nj] != cnt:
v[ni][nj] = cnt
Q.append((ni, nj))
rbw += 1
elif b==t and v[ni][nj] == 0:
v[ni][nj] = cnt
Q.append((ni, nj))
idx += 1
return [len(Q), rbw, si, sj, Q]
def find_blockgroup():
v = [[0]*N for _ in range(N)]
max_blocks = [0, 0, -1, -1, []]
cnt = 0
for i in range(N):
for j in range(N):
if block[i][j]>0 and not v[i][j]:
cnt += 1
max_blocks = max(max_blocks, bfs(i, j, v, cnt))
return max_blocks[-1]
def remove(blocks):
global res
res += len(blocks) ** 2
for br, bc in blocks:
block[br][bc] = -2
def gravity(arr):
for j in range(N):
bot = i = N-1
while -1<i:
t = arr[i][j]
if t == -1:
bot = i-1
elif t>=0:
if bot > i:
arr[bot][j] = t
arr[i][j] = -2
bot -= 1
i -= 1
return arr
def autoplay():
global block
while 1:
blocks = find_blockgroup()
if len(blocks) <= 1:
return
remove(blocks)
gravity(block)
block = gravity(rotate(block))
N, M = map(int, input().split())
block = [list(map(int, input().split())) for _ in range(N)]
dr, dc = (0, 1, 0, -1), (-1, 0, 1, 0)
res = 0
autoplay()
print(res)
풀고 나니까 그렇게 어려운 거 같진 않은데 구현은 풀수록 문제 해석 능력이 월등하게 중요한 거 같다. 보여지는 것만 읽고 예외상황이랑 고려해야 할 부분들을 빠르게 파악할수록 정확하게 풀 수 있는 거 같당. 물론 난 안 됨 ㅋ