알고리즘/문제풀이

[백준/BOJ] 14889 스타트와 링크 - JAVA - 실버1

LIRI 2025. 4. 26. 18:30

[백준/BOJ] 14889 스타트와 링크 - JAVA - 실버1

문제

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

문제 분석

조건

  • 짝수인 N명을 2팀으로 나누고, 각 팀의 시너지 차이를 최소화하는 문제이다.

풀이방법

  • 비트마스킹을 사용하여 팀을 나누어주었다.
  • 시작 조합은 각 팀에 N/2명만큼 있어야하므로 조합의 시작 부분을`1 << (N / 2) - 1`로 하고, 가장 앞 부호가 1이 되는 순간 기존과 팀원이 중복되기때문에 마지막 팀원은 2팀으로 고정되게 설정하였다.
    • `for (int i = 1 << (N / 2) - 1; i < 1 << (N - 1); i++)`
  •  조합을 구하고 팀원수가 맞는다면 각 팀의 시너지를 구해주었다.

+

  • 마지막 팀원을 고정하고 첫 부분도 고정은 했지만 비트마스킹 특성상 어쩔수없이 `1 << (N / 2) - 1` 부터 ` i < 1 << (N - 1)`까지 모든 수를 탐색하게 된다.

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int[][] board;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int N = Integer.parseInt(br.readLine());
        board = new int[N + 1][N + 1];
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= N; j++) {
                board[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        int answer = Integer.MAX_VALUE;
        List<Integer> team1;
        List<Integer> team2;

        for (int i = 1 << (N / 2) - 1; i < 1 << (N - 1); i++) {
            team1 = new ArrayList<>();
            team2 = new ArrayList<>();
            for (int j = 0; j < N; j++) {
                if (((1 << j) & i) > 0) {
                    team1.add(j + 1);
                } else {
                    team2.add(j + 1);
                }
            }
            if (team1.size() != N / 2) {
                continue;
            }
            answer = Math.min(answer, Math.abs(getSynergy(team1) - getSynergy(team2)));
        }
        System.out.println(answer);
    }

    private static int getSynergy(List<Integer> team) {
        int count = 0;
        for (int member1 : team) {
            for (int member2 : team) {
                if (member1 == member2) {
                    continue;
                }
                count += board[member1][member2];
            }
        }
        return count;
    }
}

결과

++

2년 전 풀었던 문제를 스터디를 하며 다시 풀게 되었다. 그때는 재귀로 풀었는데 요즘은 조합 문제만 보면 비트마스킹을 이용해서 문제를 풀고싶어진다.

비트마스킹으로 구현은 더 쉽게 했지만 시간복잡도에서 모든 경우의 수를 탐색하느라 손해를 봤다. 또한 리스트를 반복적으로 초기화하면서 메모리면에서도 손해를 봤다. 정답을 맞았긴했지만 다음에는 정확한 경우의 수가 정해진다면 `Next Combination`을 사용해서 풀어야겠다.

728x90