여니의 취준 준비/코딩테스트 (Java)

[17281]⚾ in Java

여니's 2022. 8. 12. 17:37

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

 

17281번: ⚾

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

www.acmicpc.net


접근 방식

(1). 4번 타자는 무조건 1번 선수

타석 순서 정하는 순열 함수를 수행하기 전에

4번타자 자리는 1번 선수로 고정시켜놓는다.


(2). 순열 함수로 타석 순서를 정한다.

이때 selected[i]=cnt가 들어가야한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.util.Arrays;
 
public class permutation {
    public static int[] array;
    public static int[] selectNum;
    public static boolean[] visited;
    public static int n;
    
    private static void permu(int cnt) {
        if (cnt==3) {
            System.out.println(Arrays.toString(selectNum));
            return;
        }
        for(int i=1; i<=n; i++) {
            if(visited[i]) continue;
            visited[i]=true;
            selectNum[cnt]=i;
            permu(cnt+1);
            selectNum[cnt]=0;
            visited[i]=false;
        }
    }
    
    public static void main(String[] args) {
        // 순열 구현
        array= new int[]{1,2,3,4,5,6,7};
        n=array.length;
        selectNum= new int[3];
        visited=new boolean[n+1];
        
        permu(0);
    }
}
cs

(3). 타순 정했으니 게임 시작


1. 한 이닝에 3아웃 -> 종료 (이닝 교체 == 공격과 수비 교체)
2. 경기 시작 전, 타순을 정해야한다. (중간에 타순 변경 불가)
3. 9번 타자까지 공을 쳤는데 이닝이 끝나지 않으면 1번 타자가 다시 타석에 선다. 
(타순은 이닝이 변경되어도 순서는 유지되어야함) 
4. 1루 -> 2루 -> 3루 -> 홈 (1점+)
5. 안타(1루타), 2루타, 3루타, 홈런, 아웃 
안타: *타자와 모든 주자*가 한 루씩 진루한다. -> 1
2루타: *타자와 모든 주자*가 두 루씩 진루한다. -> 2
3루타: *타자와 모든 주자*자가 세 루씩 진루한다. -> 3
홈런: *타자와 모든 주자*가 홈까지 진루한다. -> 4
아웃: 모든 주자는 진루하지 못하고, 공격 팀에 아웃이 하나 증가한다. -> 0

 

 


시행착오

- static 변수 초기화를 안해서 이번 문제도 역시나 헤맸다 ...

이럴거면 static 변수 쓰지 마라 ㅂㄷㅂㄷ

static 변수 초기화는 꼭 main 내에서 하는걸로 ^^ 

습관을 들이자

 

 


소스 코드

1. 방식1

순열 짤 때 원래 사용하던 방식대로 구현

selected[cnt]=i

 

4번 타석일 땐

permu(idx+1)을 호출하여 

5번 타석부터 선택을 재개한다.

 

그리고 재귀 함수 permu(idx+1)의 작업이 끝났을때

4번 타석은 여전히 선수 선택을 하면 안되므로

return을 통해 함수를 종료시킨다.

즉, return을 해줌으로써 타석을 정해주는 구문인 for문을 거치지 않는다!

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package day_0818;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.StringTokenizer;
 
public class n17281 {
    static int[] selected; // 순열로 뽑은 타석 순서
    static boolean[] visited; // 방문 체크
    static int P=9// 플레이어 수 9명
    static int maxCnt=0// 최종출력값
    static int[][] player; // 각 선수의 이닝 결과 저장배열
    static int N; // 이닝수
    
    public static void startGame() {
        int curCount=0// 현재 스코어
        int playerCnt=1// 현재 타석에 서있는 선수의 번호
        int outCount=0// 아웃 카운트
         
        // N 이닝을 반복한다.
        for (int i = 0; i < N; i++) {    
            int[] state= {0,0,0}; // 현재 주자 상황 (1,2,3루)
            outCount=0;
            // 3아웃이 되기전까지 아래 과정을 반복한다.
            while (outCount<3) {
                int pResult = player[i][selected[playerCnt]]; // 타석에 서있는 선수의 점수 (해당 이닝의)
                if (pResult==0) outCount++// 1. 아웃
                else if(pResult==1) { // 2. 안타 -> 타자와 각 주자들 1칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 3루
                        state[2]=1;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 2루
                        state[1]=1;
                        state[0]=0;
                    }
                    // 타자 -> 1루
                    state[0]=1;
                }
                else if(pResult==2) { // 2. 2루타 -> 타자와 각 주자들 2칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 3루
                        state[2]=1;
                        state[0]=0;
                    }
                    // 타자 -> 2루
                    state[1]=1;
                }
                else if(pResult==3) { // 3. 3루타 -> 타자와 각 주자들 3칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 홈
                        curCount++;
                        state[0]=0;
                    }
                    // 타자 -> 3루
                    state[2]=1;
                }
               
                else if(pResult==4) { // 4. 홈런 -> 모든 주자 들어옴
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 홈
                        curCount++;
                        state[0]=0;
                    }
                    // 타자 -> 홈
                    curCount++;
                }
                if (playerCnt==8) {
                    playerCnt=9;
                }else {                    
                    playerCnt=(playerCnt+1)%9;
                }
            }
        }
        maxCnt=Math.max(maxCnt, curCount);
        
    }
    
    public static void permu(int batIdx) {
        if(batIdx>P) { // 9번 선수까지 자리를 정해준 경우
            // 2. 순열로 정한 타순으로 게임을 진행한다.   
            startGame();
            return;
        }
        if(batIdx==4) {
            permu(batIdx+1); // 4번타석 건너뛰고 5번타석부터 선택하기
            return// 4번 타석은 아래 for문 거치지 않고 함수 종료
        }
        for (int i = 2; i <=P; i++) {
            if(visited[i]) continue;
            visited[i]=true;
            selected[batIdx]=i;
            permu(batIdx+1);
            visited[i]=false;
        }
        
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N=Integer.parseInt(br.readLine()); // 이닝 수 == 게임 수
        
        // 1. 각 선수별로 이닝 결과 입력받기
        player=new int[N][P+1];
        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int j = 1; j <=P; j++) {
                player[i][j]=Integer.parseInt(st.nextToken());
            }
        }
        visited=new boolean[P+1];
        selected=new int[P+1];
        
        // 1번 선수 -> 4번 타자 (고정)
        visited[1]=true// 선수 체크 배열 (1번타자 - 방문)
        selected[4]=1// 타석 방문 배열 (4번타자 - 1번선수)
        
        // 2.순열로 타석 순서 정하기
        permu(1); // 1번 타자는 이미 선택되어있으므로 2번 타자부터 선택하면   
        
        System.out.println(maxCnt);
    }
}
 
cs

 


2. 방식2

selected[i]=cnt

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package study;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class n17281 {
    static int[] selected; // 순열로 뽑은 타석 순서
    static boolean[] visited; // 방문 체크
    static int P=9// 플레이어 수 9명
    static int maxCnt=0// 최종출력값
    static int[][] player; // 각 선수의 이닝 결과 저장배열
    static int N; // 이닝수
    
    public static void startGame() {
        int curCount=0// 현재 스코어
        int playerCnt=0// 현재 타석에 서있는 선수의 번호
        int outCount=0// 아웃 카운트
         
        // N 이닝을 반복한다.
        for (int i = 0; i < N; i++) {            
            int[] state= {0,0,0}; // 현재 주자 상황 (1,2,3루)
            outCount=0;
            // 3아웃이 되기전까지 아래 과정을 반복한다.
            while (outCount<3) {
                int pResult = player[i][selected[playerCnt]]; // 타석에 서있는 선수의 점수 (해당 이닝의)
                if (pResult==0) outCount++// 1. 아웃
                else if(pResult==1) { // 2. 안타 -> 타자와 각 주자들 1칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 3루
                        state[2]=1;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 2루
                        state[1]=1;
                        state[0]=0;
                    }
                    // 타자 -> 1루
                    state[0]=1;
                }
                else if(pResult==2) { // 2. 2루타 -> 타자와 각 주자들 2칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 3루
                        state[2]=1;
                        state[0]=0;
                    }
                    // 타자 -> 2루
                    state[1]=1;
                }
                else if(pResult==3) { // 3. 3루타 -> 타자와 각 주자들 3칸씩 이동
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 홈
                        curCount++;
                        state[0]=0;
                    }
                    // 타자 -> 3루
                    state[2]=1;
                }
                else if(pResult==4) { // 4. 홈런 -> 모든 주자 들어옴
                    if(state[2]>0) { // 3루 -> 홈
                        curCount++;
                        state[2]=0;
                    }
                    if(state[1]>0) { // 2루 -> 홈
                        curCount++;
                        state[1]=0;
                    }
                    if(state[0]>0) { // 1루 -> 홈
                        curCount++;
                        state[0]=0;
                    }
                    // 타자 -> 홈
                    curCount++;
                }
                playerCnt=(playerCnt+1)%9;
            }
        }
        maxCnt=Math.max(maxCnt, curCount);
        
    }
    
    public static void permu(int cnt) {
        if(cnt==P) {
            // 2. 순열로 정한 타순으로 게임을 진행한다.
            startGame();
            return;
        }
        for (int i = 0; i < P; i++) {
            if(visited[i]) continue;    
            selected[i]=cnt; // 아직 이해 못함 ^^, 일단 4번 타자자리에는 타자를 넣지 않는 작용을 하는 듯
            visited[i]=true;
            permu(cnt+1);
            visited[i]=false;
            
        }
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N=Integer.parseInt(br.readLine()); // 이닝 수 == 게임 수
        
        // 1. 각 선수별로 이닝 결과 입력받기
        player=new int[N][P];
        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int j = 0; j <P; j++) {
                player[i][j]=Integer.parseInt(st.nextToken());
            }
        }
        visited=new boolean[P];
        selected=new int[P];
        
        // 1번 선수 -> 4번 타자 (고정)
        visited[3]=true
        selected[3]=0;
        
        // 2.순열로 타석 순서 정하기
        permu(1); 
        
        System.out.println(maxCnt);
    }
 
}
cs

 

 

 

 

 

'여니의 취준 준비 > 코딩테스트 (Java)' 카테고리의 다른 글

[20207] 달력 in Java  (0) 2022.08.14
[17471] 게리맨더링 in Java  (0) 2022.08.14
[4012] 요리사 in Java  (0) 2022.08.12
[*11286*] 절댓값 힙 in Java  (0) 2022.08.12
[15686] 치킨 배달 in Java  (0) 2022.08.12