anott
기록
anott
  • 분류 전체보기
    • 오라클
    • SQL
    • 알고리즘
      • 백준저지
      • 프로그래머스
      • SWEA
    • 개발 관련
    • 프론트엔드
      • TypeScript, Next.js
      • React 공식문서 읽기
hELLO · Designed By 정상우.
anott

기록

백준저지 14889번 스타트와 링크
알고리즘/백준저지

백준저지 14889번 스타트와 링크

2021. 9. 2. 23:06

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

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

 

 

코드

// 출처: 백준저지 14889번 스타트와 링크 https://www.acmicpc.net/problem/14889

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

public class BOJ14889 {
    static int N, scoreTemp;
    static ArrayList<int[]> startTeam, linkTeam;
    static boolean[] isSelectedInTeam;
    static int[][] map;
    static int[] picked, diff;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine()); // N명의 사람들
        map = new int[N][N];
        for (int i = 0; i < N; i++) { // 입력
            String[] strArr = (br.readLine()).split(" ");
            for (int j = 0; j < N; j++) {
                map[i][j] = Integer.parseInt(strArr[j]);
            }
        }

        // 1. N명의 사람들을 두 팀(각 N/2명씩)으로 나눈다.
        startTeam = new ArrayList<>(); // 스타트팀. 예: (1,2,3), (1,2,4),...
        linkTeam = new ArrayList<>(); // 링크팀. 예: (4,5,6), (3,5,6),...
        isSelectedInTeam = new boolean[N]; // true면 스타트팀, false면 링크팀
        MakeTeam(0);

        diff = new int[startTeam.size()]; // 차이
        // 2. 각 팀에서 2명씩 고르고, 능력치(ij+ji)를 각각 구해서, 모두 더한다.
        // 3. 그 후 팀끼리의 차이를 구한다.
        getScoreDiff(startTeam, 1); // 스타트팀
        getScoreDiff(linkTeam, -1); // 링크팀. (스타트팀-링크팀)을 위해 -1이 필요.

        // 4. 구한 능력치의 차이 중 최솟값을 찾는다
        int answer = diff[0];
        for (int i = 1; i < diff.length; i++) {
            answer = Math.min(answer, diff[i]); // 최솟값 찾기
        }
        System.out.println(answer); // 답
    }

    private static void MakeTeam(int cnt) { // N/2명씩 두 팀을 구하기
        if (cnt == N) {
            int counts = 0;
            for (int i = 0; i < N; i++) {
                if (isSelectedInTeam[i]) {
                    counts++;
                }
            }
            if (counts == N / 2) { // N/2만큼 구해졌다면 제대로 팀이 나뉜 것
                int[] start = new int[N / 2];
                int[] link = new int[N / 2];
                int s = 0;
                int l = 0;
                for (int i = 0; i < N; i++) {
                    if (isSelectedInTeam[i]) { // 선택되었다면 스타트팀에 넣기
                        start[s] = i;
                        s++;
                    } else { // 선택되지 않았다면 링크팀에 넣기
                        link[l] = i;
                        l++;
                    }
                }
                startTeam.add(start);
                linkTeam.add(link);
            }
            return;
        }
        isSelectedInTeam[cnt] = true;
        MakeTeam(cnt + 1);
        isSelectedInTeam[cnt] = false;
        MakeTeam(cnt + 1);
    }

    private static void getScoreDiff(ArrayList<int[]> team, int flag) {
        for (int i = 0; i < team.size(); i++) {
            scoreTemp = 0; // 점수를 우선 0으로 초기화
            int[] pick = team.get(i); // team 리스트에서 하나 고르기
            picked = new int[2]; // 구한 팀 중 2명씩 다시 고를 것
            PickTwo(0, 0, pick); // pick 팀에서 2명 고르기
            diff[i] = Math.abs(diff[i] + scoreTemp * flag);
            // 차이를 구하기 위해 스타트팀은 더하고 링크팀은 뺄 것. 차이를 구하는 것이기 때문에 절댓값.
        }
    }

    private static void PickTwo(int cnt, int start, int[] pick) { // 조합
        if (cnt == 2) { // 2명 고르면 해당 쌍의 능력치 구하기
            int a = picked[0];
            int b = picked[1];
            scoreTemp = scoreTemp + map[a][b] + map[b][a];
            return;
        }
        for (int i = start; i < pick.length; i++) {
            picked[cnt] = pick[i];
            PickTwo(cnt + 1, i + 1, pick);
        }
    }
}

 

저작자표시 비영리 (새창열림)

'알고리즘 > 백준저지' 카테고리의 다른 글

백준저지 1244번 스위치 켜고 끄기  (0) 2021.09.04
백준저지 12927번 배수 스위치  (0) 2021.09.03
백준저지 10989번 수 정렬하기 3  (0) 2021.09.01
백준저지 2669번 직사각형 네개의 합집합의 면적 구하기  (0) 2021.08.30
백준저지 10163번 색종이  (0) 2021.08.29
    '알고리즘/백준저지' 카테고리의 다른 글
    • 백준저지 1244번 스위치 켜고 끄기
    • 백준저지 12927번 배수 스위치
    • 백준저지 10989번 수 정렬하기 3
    • 백준저지 2669번 직사각형 네개의 합집합의 면적 구하기
    anott
    anott

    티스토리툴바