본문 바로가기

PS

백준 14889번_스타트와 링크 (Python)

문제

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.

i\j 1 2 3 4
1 0 1 2 3
2 4 0 5 6
3 7 1 0 2
4 3 4 5 0

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S12 + S21 = 1 + 4 = 5
  • 링크 팀: S34 + S43 = 2 + 5 = 7

1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S13 + S31 = 2 + 7 = 9
  • 링크 팀: S24 + S42 = 6 + 4 = 10

축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

 

코드

N = int(input())
S = [None]*N
for i in range(N):
    S[i] = list(map(int, input().split()))

route = []
mindif = None

def dfs(c):
    global mindif
    if c==N/2:
        team1 = 0
        team2 = 0
        for i in range(N):
            if i in route:
                for j in route:
                    team1 += S[i][j]
            else:
                for j in range(N):
                    if not (j in route):
                        team2 += S[i][j]
        if mindif == None:
            mindif = abs(team1-team2)
        elif mindif>abs(team1-team2):
            mindif = abs(team1-team2)
    else:
        if route == []:
            k = 0
        else:
            k = max(route)+1
        for i in range(k, N):
            if not (i in route):
                route.append(i)
                dfs(c+1)
                route.pop()

dfs(0)
print(mindif)

 

풀이

N/2명만큼 팀을 짠다면 상대 팀도 자동으로 결정난다. 따라서 N명중 N/2명을 중복되지 않게 뽑은 후 각 팀의 능력치의 차를 구해가면 된다.

 N은 변수이므로 N/2명을 고를 때 반복문이 사용되는 횟수를 유동적으로 조절하기 위해서 재귀함수를 써준다.(https://freshmath.tistory.com/16 참고) 이때 뽑고 있는 N/2명의 번호을 route 리스트에 저장한다.

이후 N/2명만큼 다 뽑은 뒤에는 route 리스트와 전체 참가자의 번호에서 route 리스트를 뺀 차집합 각각에 대해서 능력치를 구하고, 그 차를 구해서 최솟값을 구해주면 된다.

참고로 위 코드는 Python3으로 실행하면 시간초과가 나지만 반복문에서 빠른 성능을 보이는 PyPy3으로 실행하면 아슬아슬하게 통과한다. 아마 Python3으로 통과하려면 조금 더 최적화가 필요할 것으로 보인다.