[BOJ] 17281 : ⚾(Java)

문제 링크

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

 

17281번: ⚾

⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝 동안 게임을 진행해야 한다. 한 이닝에 3아웃이 발생하면 이닝이 종

www.acmicpc.net


💡 풀이

주어진 야구 룰에 따라 구현하면 되는 문제인데, 관건은 자바에서 따로 메서드를 제공하고 있지 않은 순열을 구현하는 부분이었던 것 같습니다. 1번 선수부터 9번 선수의 타격 순서를 비교해가며 최대값을 찾는 것이기 때문에 순열을 이용했습니다. 야구 룰에 맞게 구현만하면 되는 문제입니다. 

순열

Permutation이라고 불리는 순열을 사용해 만들 수 있는 모든 타순에 대해 탐색을 진행합니다.

...
static int[] order = new int[9];
static boolean[] select = new boolean[9];
...
select[3] = true;
...

// 순열 만들기
static void nextPermutation(int num) {
    if(num == 9) {
        game();
        return;
    }

    for (int i = 0; i < 9; i++) {
        if (select[i]) {
            continue;
        }
        select[i] = true;
        order[i] = num;
        nextPermutation(num + 1);
        select[i] = false;
    }
}

select 배열은 숫자를 사용했지에 대한 여부를 나타내고, order 배열은 순열을 담은 숫자 배열입니다. 1번 선수부터 9번 선수까지이지만, 저는 편의를 위해 0~8로 설정했습니다.

1번 선수는 4번 타자로 고정되어 있기 때문에, select[4] = true로 미리 넣어주었습니다. 

야구 플레이

다음은 야구 이닝을 진행하는 부분입니다. 

아웃 카운트가 3이 되면 해당 이닝은 종료되고 다음 이닝으로 넘어가게 됩니다. 현재 이닝이 주어진 이닝보다 크다면 야구 게임을 종료합니다. 

주의할 점은, 이닝이 끝나고 다음 이닝이 시작되면 이전 이닝의 마지막 선수의 다음 선수가 출전 한다는 것입니다. 또한, 선수를 가리키는 인덱스가 배열 크기를 넘어가면 다시 처음으로 돌아가도록 설정해주어야 합니다. 

점수를 계산하는 부분은 1루부터 3루까지 base 배열에 저장하고 해당 결과에 따라 base를 이동시키고 점수를 계산하면 됩니다. 

 static void game() {
    int totalScore = 0;
    int curInning = 1;
    int index = 0;
    int outCount = 0;

    while (curInning <= inning) {

        // Base Case : 아웃 카운트 == 3
        if (outCount == 3) {
            curInning++;
            Arrays.fill(base, 0);
            outCount = 0;
            continue;
        }

        // 현재 주자의 hit 정보
        int curHit = score[curInning - 1][order[index]];
        if (curHit == 0) {
            outCount++;
        }
        else {
            totalScore += getScoreAndSetBase(curHit);
        }
        index = index == 8 ? 0 : index + 1;
    }

    answer = Math.max(answer, totalScore);
}

static int getScoreAndSetBase(int hit) {
    int result = 0;

    base[0] = 1;
    switch (hit) {
        case 1:
            result += base[3];
            base[3] = base[2];
            base[2] = base[1];
            base[1] = base[0];
            base[0] = 0;
            break;
        case 2:
            result += base[2] + base[3];
            base[3] = base[1];
            base[2] = base[0];
            base[1] = base[0] = 0;
            break;
        case 3:
            result += base[3] + base[2] + base[1];
            base[3] = base[0];
            base[2] = base[1] = base[0] = 0;
            break;
        case 4:
            result = base[3] + base[2] + base[1] + base[0];
            Arrays.fill(base, 0);
            break;
    }

    return result;
}

전체 코드

전체적인 코드는 다음과 같습니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Q17281 {
    static int inning, answer;
    static int[] order = new int[9];
    static boolean[] select = new boolean[9];
    static int[] base;
    static int[][] score;
    /*
    1 : 안타
    2 : 2루타
    3 : 3루타
    4 : 홈런
    0 : 아웃
     */

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

        inning = Integer.parseInt(br.readLine());
        base = new int[4]; // 1 : 1루 주자, 2 : 2루 주자, 3 : 3루 주자

        score = new int[inning][9];
        for (int i = 0; i < inning; i++) {
            st = new StringTokenizer(br.readLine());
            for (int person = 0; person < 9; person++) {
                score[i][person] = Integer.parseInt(st.nextToken());
            }
        }

        // 1번 선수는 4번 타자로 고정되어 있다.
        select[3] = true;

        answer = Integer.MIN_VALUE;
        nextPermutation(1);

        System.out.println(answer);
    }

    // 순열 만들기
    static void nextPermutation(int num) {
        if(num == 9) {
            game();
            return;
        }

        for (int i = 0; i < 9; i++) {
            if (select[i]) {
                continue;
            }
            select[i] = true;
            order[i] = num;
            nextPermutation(num + 1);
            select[i] = false;
        }
    }

    static void game() {
        int totalScore = 0;
        int curInning = 1;
        int index = 0;
        int outCount = 0;

        while (curInning <= inning) {

            // Base Case : 아웃 카운트 == 3
            if (outCount == 3) {
                curInning++;
                Arrays.fill(base, 0);
                outCount = 0;
                continue;
            }

            // 현재 주자의 hit 정보
            int curHit = score[curInning - 1][order[index]];
            if (curHit == 0) {
                outCount++;
            }
            else {
                totalScore += getScoreAndSetBase(curHit);
            }
            index = index == 8 ? 0 : index + 1;
        }

        answer = Math.max(answer, totalScore);
    }

    static int getScoreAndSetBase(int hit) {
        int result = 0;

        base[0] = 1;
        switch (hit) {
            case 1:
                result += base[3];
                base[3] = base[2];
                base[2] = base[1];
                base[1] = base[0];
                base[0] = 0;
                break;
            case 2:
                result += base[2] + base[3];
                base[3] = base[1];
                base[2] = base[0];
                base[1] = base[0] = 0;
                break;
            case 3:
                result += base[3] + base[2] + base[1];
                base[3] = base[0];
                base[2] = base[1] = base[0] = 0;
                break;
            case 4:
                result = base[3] + base[2] + base[1] + base[0];
                Arrays.fill(base, 0);
                break;
        }

        return result;
    }
}