diff --git "a/INSEA-99/week01/week10/10026_\354\240\201\353\241\235\354\203\211\354\225\275.py" "b/INSEA-99/week01/week10/10026_\354\240\201\353\241\235\354\203\211\354\225\275.py" new file mode 100644 index 0000000..198e5ee --- /dev/null +++ "b/INSEA-99/week01/week10/10026_\354\240\201\353\241\235\354\203\211\354\225\275.py" @@ -0,0 +1,92 @@ +# pypy3 +# 시간(ms) : 152 +# 공간(KB) : 115588 +# +# 공유 : +# - 정상인과 적록색약이 겹치는 구역이 있어 동시에 탐색하는게 좋지 않을까 생각 +# - 함수는 한가지 기능만 구현하는게 좋은데, 위 방식은 2가지를 한 번에 탐색하려해서 코드 복잡도가 올라감 +# - 오히려 코드 리뷰/유지보수 측면에서 안좋고 디버깅하기 어려움 +# - 결론 : 따로 탐색하는게 낫다. 미세한 성능차이를 얻으려다 많은 것을 잃는다약간의 + +import sys +from collections import deque +input = sys.stdin.readline +# 방향: ↑, ↓, ←, → +dr = [-1, 1, 0, 0] +dc = [0, 0, -1, 1] + +def bfs(r, c, is_normal, is_colorblind): + """ + 정상인과 적록색약인 사람의 구역을 동시에 탐색하는 BFS + :param r, c: 시작 좌표 + :param is_normal: 정상인 시각으로 탐색할지 여부 + :param is_colorblind: 적록색약 시각으로 탐색할지 여부 + """ + global n + dq = deque([(r, c, is_normal, is_colorblind)]) + + while dq: + r, c, is_normal, is_colorblind = dq.popleft() # BFS는 FIFO + + # 상하좌우 4방향 탐색 + for d in range(4): + nr, nc = r + dr[d], c + dc[d] + + # 범위 체크: 벗어나면 스킵 + if not (0 <= nr < n and 0 <= nc < n): + continue + + n_is_normal = n_is_colorblind = False + + # 정상인 시각: 같은 색(R, G, B)끼리만 연결 + if is_normal and not normal_visited[nr][nc] and area[nr][nc] == area[r][c]: + normal_visited[nr][nc] = True + n_is_normal = True + + # 적록색약 시각: R과 G는 같은 색으로 취급, B는 따로 + if is_colorblind and not colorblind_visited[nr][nc]: + # (현재와 다음이 모두 R 또는 G) 또는 (같은 색)이면 연결 + if (area[r][c] in 'RG' and area[nr][nc] in 'RG') or area[r][c] == area[nr][nc]: + colorblind_visited[nr][nc] = True + n_is_colorblind = True + + # 하나라도 방문했으면 큐에 추가 + if n_is_normal or n_is_colorblind: + dq.append((nr, nc, n_is_normal, n_is_colorblind)) + + +# 입력 +n = int(input()) +area = [list(input().strip()) for _ in range(n)] + +# 구역 개수 카운트 +normal_area = 0 +colorblind_area = 0 + +# 방문 체크 배열 +normal_visited = [[False] * n for _ in range(n)] +colorblind_visited = [[False] * n for _ in range(n)] + +# 모든 칸을 순회하며 새로운 구역 발견 시 BFS 시작 +for r in range(n): + for c in range(n): + is_normal = False + is_colorblind = False + + # 정상인 시각에서 미방문 구역이면 새 구역 시작 + if not normal_visited[r][c]: + normal_visited[r][c] = True + is_normal = True + normal_area += 1 + + # 적록색약 시각에서 미방문 구역이면 새 구역 시작 + if not colorblind_visited[r][c]: + colorblind_visited[r][c] = True + is_colorblind = True + colorblind_area += 1 + + # 하나라도 새 구역이면 BFS로 연결된 칸 모두 방문 처리 + if is_normal or is_colorblind: + bfs(r, c, is_normal, is_colorblind) + +print(normal_area, colorblind_area) \ No newline at end of file diff --git "a/INSEA-99/week01/week10/1967_\355\212\270\353\246\254\354\235\230_\354\247\200\353\246\204.py" "b/INSEA-99/week01/week10/1967_\355\212\270\353\246\254\354\235\230_\354\247\200\353\246\204.py" new file mode 100644 index 0000000..2cab26b --- /dev/null +++ "b/INSEA-99/week01/week10/1967_\355\212\270\353\246\254\354\235\230_\354\247\200\353\246\204.py" @@ -0,0 +1,42 @@ +# pypy3 +# 시간(ms) : 116 +# 공간(KB) : 245360 +# +# 공유 : +# - 예시가 이진트리라서 이진트리인줄 알았는데 그런 언급은 없어서 3개 이상의 자식 노드 고려 필요했음 + +import sys +input = sys.stdin.readline +sys.setrecursionlimit(10**5) + +def dfs(root): + """현재 노드에서 가장 긴 경로의 길이를 반환""" + global ans + visited[root] = True + dist = [0, 0] # 가장 긴 두 경로를 저장 + for neighbor, weight in adj[root]: + if not visited[neighbor]: + maintain_top_two(dist, dfs(neighbor) + weight) # 자식 노드로부터 가장 긴 경로 + 간선 가중치 + + ans = max(ans, dist[0] + dist[1]) # 가장 긴 두 경로를 합쳐서 지름 후보 갱신 + return dist[0] + +def maintain_top_two(list, n): + """리스트에서 가장 큰 두 값을 유지""" + if n > list[0]: + list[1] = list[0] + list[0] = n + elif n > list[1]: + list[1] = n + +n = int(input()) +adj = [[] for _ in range(n+1)] +visited = [False] * (n+1) +for _ in range(n-1): + u, v, w = map(int, input().split()) + adj[u].append((v, w)) + adj[v].append((u, w)) + +ans = 0 +dfs(1) +print(ans) \ No newline at end of file diff --git "a/INSEA-99/week01/week10/2580_\354\212\244\353\217\204\354\277\240.py" "b/INSEA-99/week01/week10/2580_\354\212\244\353\217\204\354\277\240.py" new file mode 100644 index 0000000..cbda809 --- /dev/null +++ "b/INSEA-99/week01/week10/2580_\354\212\244\353\217\204\354\277\240.py" @@ -0,0 +1,72 @@ +# pypy3 +# 시간(ms) : 540 +# 공간(KB) : 241236 + +import sys +input = sys.stdin.readline +sys.setrecursionlimit(10**5) + +def backtrack(depth): + """depth번째 빈 칸을 채우는 백트래킹 함수""" + if depth == total_blanks: # 모든 빈 칸을 채웠으면 + return True + + row_idx, col_idx = blank_positions[depth] # 튜플 언패킹으로 가독성 향상 + box_idx = box_number[row_idx][col_idx] # 반복 계산 제거 + + for num in range(9): # 1~9까지 시도 (인덱스 0~8) + # 같은 행, 열, 3x3 박스에 num+1이 없는지 한 번에 체크 (is_valid 함수 인라인화) + if not (used_in_row[row_idx][num] or used_in_col[col_idx][num] or used_in_box[box_idx][num]): + # 숫자 배치 + board[row_idx][col_idx] = num + 1 + used_in_row[row_idx][num] = 1 + used_in_col[col_idx][num] = 1 + used_in_box[box_idx][num] = 1 + + if backtrack(depth + 1): # 다음 빈 칸으로 이동 + return True + + # 백트래킹: 숫자 제거 + board[row_idx][col_idx] = 0 + used_in_row[row_idx][num] = 0 + used_in_col[col_idx][num] = 0 + used_in_box[box_idx][num] = 0 + + return False + + +# 입력 받기: 9x9 스도쿠 보드 +board = [] +for _ in range(9): + board.append(list(map(int, input().split()))) + +# 각 칸이 속한 3x3 박스 번호 (0~8) +# 0 1 2 +# 3 4 5 +# 6 7 8 +box_number = [[0,0,0,1,1,1,2,2,2] for _ in range(3)] + \ + [[3,3,3,4,4,4,5,5,5] for _ in range(3)] + \ + [[6,6,6,7,7,7,8,8,8] for _ in range(3)] + +blank_positions = [] # 빈 칸(0인 칸)의 위치 저장 +total_blanks = 0 # 빈 칸의 총 개수 + +# 각 행, 열, 3x3 박스에서 1~9 숫자 사용 여부 체크 (인덱스 0~8이 1~9를 의미) +used_in_row = [[0] * 9 for _ in range(9)] # used_in_row[i][n]: i행에 n+1이 있으면 1 +used_in_col = [[0] * 9 for _ in range(9)] # used_in_col[j][n]: j열에 n+1이 있으면 1 +used_in_box = [[0] * 9 for _ in range(9)] # used_in_box[b][n]: b번 박스에 n+1이 있으면 1 + +# 초기 보드 분석: 빈 칸 찾기 및 사용된 숫자 체크 +for i in range(9): + for j in range(9): + if board[i][j] == 0: # 빈 칸 발견 + blank_positions.append([i, j]) + total_blanks += 1 + else: # 이미 채워진 칸 + num = board[i][j] - 1 # 1~9를 0~8 인덱스로 변환 + used_in_row[i][num] = 1 + used_in_col[j][num] = 1 + used_in_box[box_number[i][j]][num] = 1 + +backtrack(0) # 0번째 빈 칸부터 시작 +for row in board: print(*row) \ No newline at end of file diff --git a/INSEA-99/week01/week10/9663_N-Queen.py b/INSEA-99/week01/week10/9663_N-Queen.py new file mode 100644 index 0000000..bc8f08d --- /dev/null +++ b/INSEA-99/week01/week10/9663_N-Queen.py @@ -0,0 +1,44 @@ +# pypy3 +# 시간(ms) : 4760 +# 공간(KB) : 245896 + +import sys +input = sys.stdin.readline +sys.setrecursionlimit(10**6) + +def backtrack(row): + """row번째 행에 퀸을 배치하는 백트래킹 함수""" + if row == N + 1: # 모든 행에 퀸을 배치했으면 + count[0] += 1 + else: + for col in range(1, N + 1): # 각 열에 퀸을 배치 시도 + if used_col[col] == 1: continue # 이미 해당 열에 퀸이 있으면 스킵 + if is_safe(row, col): # 대각선 체크 + # 퀸 배치 + used_col[col] = 1 + diag_sum[row + col] = 1 # 우상향 대각선 (row+col 값이 같음) + diag_sub[row - col] = 1 # 좌하향 대각선 (row-col 값이 같음) + + backtrack(row + 1) # 다음 행으로 이동 + + # 백트래킹: 퀸 제거 + used_col[col] = 0 + diag_sum[row + col] = 0 + diag_sub[row - col] = 0 + +def is_safe(row, col): + """(row, col) 위치에 퀸을 놓을 수 있는지 대각선 체크""" + if diag_sum[row + col] == 1 or diag_sub[row - col] == 1: + return False + return True + +# 변수 초기화 +count = [0] # 경우의 수 (리스트로 선언하여 함수 내에서 수정 가능) +N = int(input()) # 체스판 크기 +used_col = [0] * (N + 1) # 각 열에 퀸이 있는지 체크 +diag_sum = [0] * (N * 2 + 1) # 우상향 대각선 체크 (row+col 인덱스) +diag_sub = [0] * (N * 2 - 1) # 좌하향 대각선 체크 (row-col 인덱스) + +backtrack(1) # 1번 행부터 시작 +print(count[0]) +