[백준/파이썬] 14889

2025. 2. 14.·백준

https://www.acmicpc.net/problem/14889

스타트와 링크(삼성 SW 역량 테스트 기출 문제 2) - 실버 1

💫 알고리즘

백트래킹

후보 해를 한 단계씩 구축하며, 조건에 맞지 않는 경우 이전 단계로 되돌아가 다른 선택지를 탐색

깊이 우선 탐색(DFS)과 유사하며, 유망하지 않은 경로를 조기에 배제하여 탐색 효율을 높임

퍼즐, 조합 최적화, N-Queen 문제 등 복잡한 문제에서 가능한 해의 공간을 체계적으로 탐색


💡 풀이방향

🐢 백트래킹을 사용하여 모든 가능한 팀 조합을 탐색하며 차이 최소화

1️⃣ N명의 사람을 두 개의 팀(스타트 팀과 링크 팀)으로 나누어야 함

: DFS를 이용하여 N/2명의 스타트 팀을 선택하면 나머지는 자동으로 링크 팀

2️⃣ 팀 간 능력치 차이를 최소화

3️⃣ 팀의 능력치는 S[i][j] + S[j][i]

4️⃣ N은 짝수이며, N/2명씩 나누어야 함

5️⃣ 백트래킹(DFS)을 사용하여 가능한 모든 팀 조합 탐색하며 차이 최소화

: 모든 조합을 탐색하면서 |스타트 팀 - 링크 팀|의 최솟값을 저장


🌟 코드 구현 + 👀 풀이

[전체 코드]

import sys
input = sys.stdin.readline

N = int(input())
S = [list(map(int, input().split())) for _ in range(N)]
visited = [False] * N
result = sys.maxsize

def dfs(depth, idx):
    global result

    if depth == N // 2:
        start = 0
        link = 0

        for i in range(N):
            for j in range(N):
                if visited[i] and visited[j]:
                    start += S[i][j]
                elif not visited[i] and not visited[j]:
                    link += S[i][j]

        result = min(result, abs(start - link))
        return

    for i in range(idx, N):
        if not visited[i]:
            visited[i] = True
            dfs(depth + 1, i + 1)
            visited[i] = False

dfs(0, 0)
print(result)

S = [list(map(int, input().split())) for _ in range(N)]

능력치 배열

visited = [False] * N

방문 여부; 스타트 팀과 링크 팀 구분을 위해

백트래킹(DFS): dfs함수

def dfs(depth, idx): #depth: 현재 선택한 스타트 팀원 수/ idx: 현재 탐색할 인덱스(중복 방지) 
    global result

    if depth == N // 2: # 팀 구분 완료
        start = 0
        link = 0

        for i in range(N):
            for j in range(N):
                if visited[i] and visited[j]: # 스타트 팀 능력치 합산
                    start += S[i][j]
                elif not visited[i] and not visited[j]: # 나머지(링크 팀) 능력치 합산
                    link += S[i][j]

        result = min(result, abs(start - link)) # 팀 능력치 차이 최솟값 갱신
        return

    for i in range(idx, N): # idx 이후부터 탐색(중복 방지)
        if not visited[i]: # 방문 X(팀 미정인 사람)
            visited[i] = True # 스타트 팀에 넣기
            dfs(depth + 1, i + 1) # 다음 사람 탐색
            visited[i] = False # 백트래킹(모든 경우의 수 탐색 위해 초기화)

🤔 visited 리스트로 어떻게 팀을 구분하는 건가요? 

🐢 간단하게 생각하시면 돼요. N/2명의 사람이 스타트 팀이 되면, 자동으로 나머지 사람들은 링크 팀이 되겠죠? visited[i] = True인 사람은 스타트 팀이, visited[i] = False인 사람은 링크 팀이 되는 거죠. 이에 따라 if-elif문을 두는 거고요.


🎁 더 보기

🐢 위의 문제는 조합으로도 풀 수 있습니다!

import sys
from itertools import combinations
input = sys.stdin.readline

N = int(input())  
S = [list(map(int, input().split())) for _ in range(N)]  
result = float('inf')

# 모든 조합 탐색(N명 중 절반을 스타트 팀으로 선택)
for start in combinations(range(N), N // 2):
    link = list(set(range(N)) - set(start))  # 나머지가 자동으로 링크 팀

    # 스타트 팀과 링크 팀 능력치 계산
    start_stat = sum(S[i][j] + S[j][i] for i, j in combinations(start, 2))
    link_stat = sum(S[i][j] + S[j][i] for i, j in combinations(link, 2))

    # 최소 차이 갱신
    result = min(result, abs(start_stat - link_stat))

print(result)

for start in combinations(range(N), N // 2):

N명 중 N/2명을 뽑아 스타트 팀으로 만들고

link = list(set(range(N)) - set(start))

스타트 팀을 제외한 나머지가 링크 팀

start_stat = sum(S[i][j] + S[j][i] for i, j in combinations(start, 2))

link_stat = sum(S[i][j] + S[j][i] for i, j in combinations(link, 2))

팀 내에서 두 명을 뽑는 모든 조합의 능력치 합

🐢 combinations는 조합을 미리 생성하여 불필요한 연산 없이 팀을 나눌 수 있고, 최적화가 되어 있어 훨씬 빨라요!!

저작자표시 비영리 변경금지 (새창열림)

'백준' 카테고리의 다른 글

[백준/파이썬] 10986  (0) 2025.02.16
[백준/파이썬] 16139  (0) 2025.02.15
[백준/Python(파이썬)] 14888  (1) 2025.02.13
[백준/Python(파이썬)] 2580  (0) 2025.02.12
[백준/Python(파이썬)] 9663  (0) 2025.02.11
'백준' 카테고리의 다른 글
  • [백준/파이썬] 10986
  • [백준/파이썬] 16139
  • [백준/Python(파이썬)] 14888
  • [백준/Python(파이썬)] 2580
우는거북이
우는거북이
  • 우는거북이
    거북이는 울고 있다
    우는거북이
  • 전체
    오늘
    어제
    • 알아보기 (74) N
      • AI (4)
      • 언어 (16)
        • Python (15)
        • C언어 (1)
      • 알고리즘 (7)
      • 백준 (22)
      • 자료구조 (10)
      • 컴퓨터네트워크 (6)
      • 운영체제 (1)
      • 데이터통신 (8) N
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
우는거북이
[백준/파이썬] 14889
상단으로

티스토리툴바