같은 집합 내에 속해있다면 해당 뉴런은 끊어내야 하는 뉴런이므로 연산 횟수를 하나 증가시킨다.
모든 뉴런들에 대해 같은 집합에 속해있는지 검사한다.
다른 집합에 속해있다면, 두 집합을 Union 해주고 연산 횟수를 하나 증가시킨다.
연산 횟수를 출력시켜준다.
소스 코드
import sys
sys.setrecursionlimit(10**6)
input = lambda: sys.stdin.readline().rstrip()
N, M = map(int, input().split())
parent = [i for i in range(N+1)]
def find(parent, a):
if parent[a] != a:
parent[a] = find(parent, parent[a])
return parent[a]
def union(parent, a, b):
p1 = find(parent, a)
p2 = find(parent, b)
if p1 != p2:
parent[p1] = p2
answer = 0
for _ in range(M):
a, b = map(int, input().split())
if find(parent, a) != find(parent, b):
union(parent, a, b)
else:
answer += 1
parent_node = find(parent, 1)
idx = 1
for i in range(2, N+1):
if find(parent, i) != parent_node:
union(parent, i, idx)
parent_node = find(parent, i)
idx = i
answer += 1
print(answer)
전체 간선의 개수의 두배에서 마지막에 방문하는 정점을 방문하기 위해 지나온 간선의 개수를 빼주어서 출력
소스 코드
import sys
sys.setrecursionlimit(10**6)
input = lambda: sys.stdin.readline().rstrip()
left = dict()
right = dict()
N = int(input())
parent = [0] * (N+1)
node_count = 0
for _ in range(N):
a, b, c = map(int, input().split())
left[a] = b
right[a] = c
if b != -1:
parent[b] = a
node_count += 1
if c != -1:
parent[c] = a
node_count += 1
# 마지막 노드 구하는 파트
last_node = 0
def traverse(node):
global last_node
if node == -1:
return
traverse(left[node])
last_node = node
traverse(right[node])
traverse(1)
edge_count = node_count * 2
movement = 0
# 마지막 노드까지 이동 경로의 거리 구함
while last_node != 1:
movement += 1
last_node = parent[last_node]
print(edge_count - movement)
여기서, DP[i][j][k]에서 i가 의미하는것은 현재 위치, j가 의미하는것은 현재 문자열이 두루마리의 몇번째에 적힌 문자열인지, k가 의미하는 것은 0일땐 악마의 돌다리, 1일땐 천사의 돌다리이다.
점화식을 이용하여 전체 경우의 수를 구한 전체 DP테이블에서 두루마리의 마지막 문자까지 간 경우의 수들만 더해주면 된다.
소스 코드
import sys
input = lambda: sys.stdin.readline().rstrip()
target = input()
s1 = input()
s2 = input()
dp = [[[0] * 2 for _ in range(len(target))] for _ in range(len(s1))]
for i in range(len(s1)):
if s1[i] == target[0]:
dp[i][0][0] = 1
if s2[i] == target[0]:
dp[i][0][1] = 1
for i in range(len(s1)):
for j in range(1, len(target)):
if s1[i] == target[j]:
for k in range(i):
dp[i][j][0] += dp[k][j-1][1]
if s2[i] == target[j]:
for k in range(i):
dp[i][j][1] += dp[k][j-1][0]
answer = 0
for i in range(len(s1)):
answer += (dp[i][len(target)-1][0] + dp[i][len(target)-1][1])
print(answer)
설명하자면, dp[i-1][j]->dp[i][j]는 i에서 칠하지 않는 경우의 수이고 dp[i-2][j-1]은 i에서 칠하는 경우의 수이다.
DP를 두번 진행한다. 한번은 맨 첫번째 색상환을 칠하는 경우, 다른 한번은 첫번째 색상환을 칠하지 않는 경우이다. 이 때 주의해야 할 점은 첫번째 색상환을 칠하는 여부에 따라 dp 테이블 초기화 방식이 다르다는 점이다. 이 점 때문에 시간 많이 잡아먹음..ㅋㅋ
맨 첫번째 색상환을 칠하는 경우에는 마지막 색상환을 칠해선 안되므로 dp[N-1][K]
맨 첫번째 색상환을 칠하지 않는 경우는 마지막 색상환을 칠할 수 있으므로 dp[N][K]
두 합을 구해서 출력시켜준다.
소스 코드
import sys
input = lambda: sys.stdin.readline().rstrip()
N = int(input())
K = int(input())
answer = 0
selected = True
div = 1000000003
for i in range(2):
dp = [[0] * (K+1) for _ in range(N+1)]
for i in range(1, N+1):
if not selected:
dp[i][1] = i-1
dp[i][0] = 1
else:
dp[i][1] = 1
dp[i][0] = 0
for i in range(2, N+1):
for j in range(2, K+1):
dp[i][j] += dp[i-1][j]
if i >= 2 and j >= 1:
dp[i][j] += dp[i-2][j-1]
dp[i][j] %= div
if selected:
answer += dp[N-1][K]
else:
answer += dp[N][K]
answer %= div
selected = not selected
print(answer)
기준 블록을 왼쪽 위에서 오른쪽 아래 순서로 골라서 블록 그룹을 찾으므로 현재 고른 블록이 기준 블록의 행이 가장 크고 열이 가장 큰 것이다. 따라서 크기가 같고 무지개 블록의 수도 같은 경우는 갱신시켜 주어야 한다.
(1)에서 구한 블록 그룹을 모두 제거한다. 이 때 점수도 같이 구해준다.
제거 표시는 -2로 표시하고, 점수는 블록 그룹 내 블록의 수 제곱을 해준다.
중력 기능을 구현한다.
가장 아래 행에서부터 시작해서 하나하나의 요소들을 아래에 -2가 나타나지 않을때까지 당겨준다.
회전 기능을 구현한다.
matrix[i][j] = matrix[j][len(matrix[0])-1-i]
구현 순서에 맞추어서 전체 기능을 조합한다. 이 때, 최대 블록 그룹을 구했을 때, 그룹이 없거나 그룹 내 블록의 수가 1개인 경우에 게임을 종료시킨다.
소스 코드
import sys
from collections import deque
import copy
input = lambda: sys.stdin.readline().rstrip()
N, M = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(N)]
def bfs(matrix, startX, startY):
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]
queue = deque([[startX, startY]])
block_color = matrix[startX][startY]
matrix[startX][startY] = -1
block_count = 1
rainbow = []
block = [[startX, startY]]
while queue:
x, y = queue.popleft()
for i in range(4):
nx, ny = x + dx[i], y + dy[i]
if 0 <= nx and nx < N and 0 <= ny and ny < N:
if matrix[nx][ny] == block_color or matrix[nx][ny] == 0:
queue.append([nx, ny])
block.append([nx, ny])
block_count += 1
if matrix[nx][ny] == 0:
rainbow.append([nx, ny])
matrix[nx][ny] = -1
for nx, ny in rainbow:
matrix[nx][ny] = 0
return block, block_count, len(rainbow)
def find_max_block(target):
matrix = copy.deepcopy(target)
max_block, max_block_count, max_rainbow = None, 0, 0
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j] > 0:
block, block_count, rb_len = bfs(matrix, i, j)
if max_block_count < block_count:
max_block, max_block_count, max_rainbow = block, block_count, rb_len
elif max_block_count == block_count:
if max_rainbow <= rb_len:
max_block, max_block_count, max_rainbow = block, block_count, rb_len
return max_block
def destroy(matrix, block):
for x, y in block:
matrix[x][y] = -2
def gravity(matrix):
for i in range(len(matrix)-2, -1, -1):
for j in range(len(matrix[0])):
index = i
if matrix[i][j] == -1:
continue
while index+1 != N and matrix[index+1][j] == -2:
matrix[index+1][j] = matrix[index][j]
matrix[index][j] = -2
index += 1
def rotate(matrix):
new_matrix = copy.deepcopy(matrix)
for i in range(len(matrix)):
for j in range(len(matrix[0])):
new_matrix[i][j] = matrix[j][len(matrix)-1-i]
return new_matrix
score = 0
while True:
block = find_max_block(matrix)
if block == None:
break
if len(block) <= 1:
break
score += (len(block) ** 2)
destroy(matrix, block)
gravity(matrix)
matrix = rotate(matrix)
gravity(matrix)
print(score)
이 때, 블록이 바닥에 닿지 않는다면, 해당 블록을 이동시켜주어야 하니 잠시 저장시켜 둔다.
바닥에 닿지 않는 블록이 있는 경우, 바닥에 닿지 않는 블록들을 몇칸 내려야 다른 블록에 충돌하는지 벽에 닿는지 검사하고, 해당 칸수만큼 블록 내 모든 미네랄들을 내려준다.
1-3번 과정을 반복한다.
소스 코드
import sys
from collections import deque
import copy
input = lambda: sys.stdin.readline().rstrip()
R, C = map(int, input().split())
matrix = [list(input()) for _ in range(R)]
N = int(input())
throws = map(int, input().split())
def bfs(matrix, sx, sy):
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]
block = [[sx, sy]]
queue = deque([[sx, sy]])
matrix[sx][sy] = '.'
down = False if sx == R-1 else True
while queue:
sx, sy = queue.popleft()
for i in range(4):
nx, ny = sx + dx[i], sy + dy[i]
if nx >= 0 and nx < R and ny >= 0 and ny < C and \
matrix[nx][ny] == 'x':
down = False if nx == R-1 else down
block.append([nx, ny])
queue.append([nx, ny])
matrix[nx][ny] = '.'
return block, down
def movedown(matrix, block):
for x, y in block:
matrix[x][y] = '.'
movement_count = 0
# 몇칸 이동해야하는지 구함
for i in range(1, R):
for x, y in block:
if x+i+1 == R or matrix[x+i+1][y] == 'x':
movement_count = i
break
if movement_count != 0:
break
for x, y in block:
matrix[x+movement_count][y] = 'x'
def check(matrix):
target = None
cp_matrix = copy.deepcopy(matrix)
for i in range(len(cp_matrix)):
for j in range(len(cp_matrix[0])):
if cp_matrix[i][j] == 'x':
block, down = bfs(cp_matrix, i, j)
if down:
target = block
break
if target:
break
if target:
movedown(matrix, target)
left = True
for throw in throws:
if left:
for j in range(C):
if matrix[R-throw][j] == 'x':
matrix[R-throw][j] = '.'
break
else:
for j in range(C-1, -1, -1):
if matrix[R-throw][j] == 'x':
matrix[R-throw][j] = '.'
break
check(matrix)
left = not left
for m in matrix:
print("".join(m))