[Unsolved][JAVA] 백준 17281 ⚾️ (야구, ⚾)
2022. 8. 18.
반응형

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

 

17281번: ⚾

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

www.acmicpc.net

 

1. 서론 

 

개인적으로 어려웠던 문제... 코드가 엄청 복잡하거나 그런 건 아닌데 문제 자체를 제대로 이해하는데 며칠이 걸렸다.

문제를 어떻게 이해하냐에 따라 풀이가 완전 달라지다 보니... 문제가 풀릴 리가 없지. 어쨌든 순열을 활용하는 구현 문제이다.

 

2. 문제 풀이

 

N이닝동안 게임이 진행되고 아웃이 3번 발생하면 이닝이 바뀐다.

게임을 시작하기 전에 타자의 순서를 정하고 그 순서대로 이닝이 바뀌어도 계속 게임이 진행된다.

그리고 같은 타자가 이닝별로 낼 수 있는 결과가 주어진다.

  • 안타: 타자와 모든 주자가 한 루씩 진루한다. (1)
  • 2루타: 타자와 모든 주자가 두 루씩 진루한다. (2)
  • 3루타: 타자와 모든 주자가 세 루씩 진루한다. (3)
  • 홈런: 타자와 모든 주자가 홈까지 진루한다. (4)
  • 아웃: 모든 주자는 진루하지 못하고, 공격 팀에 아웃이 하나 증가한다. (0)

이를 통해 N이닝을 진행한 후 얻을 수 있는 최대 점수가 나오도록 타자의 순서를 배열해서 계산하는 것이 문제이다.

 

백준 문제가 이렇게 친절하게 적혀있으면 나도 헤매지 않았을텐데...

 

입력을 다 받은 후에 타자 순서를 순열로 돌려준다. 그리고 그 돌린 값으로 점수를 계산한 후 점수 계산을 해준다.

계산할 때 3개짜리 배열을 놓고 안타, 2루타, 홈런에 따라서 베이스 어디에 선수가 있는지 체크하고 3루를 지나면 점수로 계산해준다.

이때 내가 실수한 점이 선수들을 일단 3루부터 먼저 움직이게 한 다음 새로운 선수를 넣어야 하는데 1루부터 하고 순서를 엉망으로 해서 계산이 엉켰다. 1루부터 하면 거기 새로 들어온 선수들도 처리하게 되기 때문에 그러면 안 되는데... 차마 생각지 못함 ㅎ

 

https://steady-coding.tistory.com/35

 

[BOJ] 백준 17281번 : ⚾ (JAVA)

문제의 링크 : https://www.acmicpc.net/problem/17281 17281번: ⚾ ⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝 동안 게임을

steady-coding.tistory.com

문제가 영 안 풀려서 여기 코드를 참조했다. (문제 이해도 잘못하고... 중간에 계산도 틀렸을 때마다 참조 ㅎ)

 

3. 코드 설명

 

public class Main {
	
	static int n, ans;
	static int[] order; //타자 순서
	static int[][] a;
	static boolean[] select; //타자 순서 체크
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		n = Integer.parseInt(br.readLine());
		
		a = new int[n][9];
		for (int i = 0; i < n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			for (int j = 0; j < 9; j++)
				a[i][j] = Integer.parseInt(st.nextToken());
		}
		
		select = new boolean[9];
		order = new int[9];
		select[3] = true; //1번타자 위치 4번으로 고정
		order[3] = 0;
		ans = 0;
		
		perm(1);
		
		bw.write(ans + "\n");
	    bw.flush(); bw.close(); br.close();
	}
	
	public static void perm(int cnt) { //순열(타자 순서 구하기)
		if (cnt == 9) {
			play();
			return;
		}
		for (int i = 0; i < 9; i++) {
			if (select[i]) continue;
			select[i] = true;
			order[i] = cnt; // 타자치는 순서를 배열에 담아준다
			perm(cnt + 1);
			select[i] = false;
		}
		
	}
	
	public static void play() { // 점수 체크
		int score = 0, start = 0;
		int[] base;
		
		for (int k = 0; k < n; k++) { //이닝만큼 반복
			base = new int[3];
			int out = 0;
			
			outer: while(true) { //점수 계산
				for (int i = start; i < 9; i++) {
					int hitter = a[k][order[i]]; //타자(정해진 순서대로 바뀜)
					
					if (hitter == 0)
						out++;
					if (hitter == 1) {
						for (int j = 2; j >= 0; j--) {
							if (base[j] != 0) {
								while(base[j] != 0) {
									if (j == 2) score++;
									else base[j + 1]++;
									base[j]--;
								}
							}
						}
						base[0]++;
					}
					
					else if (hitter == 2) {
						for (int j = 2; j >= 1; j--) {
							if (base[j] != 0) {
								while(base[j] != 0) {
									score++;
									base[j]--;
								}
							}
						}
						base[2] += base[0];
						base[0] = 0;
						base[1]++;
					}
					
					else if (hitter == 3 || hitter == 4) {
						for (int j = 2; j >= 0; j--) {
							if (base[j] != 0) {
								while(base[j] != 0) {
									score++;
									base[j]--;
								}
							}
						}
						if (hitter == 3) base[2]++;
						else score++;
					}
                    if (out == 3) { //이닝이 끝날 경우 break
                    	start = i + 1; //다음타순 넘겨줌
                        if (start == 9) 
                            start = 0;
                        break outer;
                    }
						
				}
				start = 0;
			}
		}
		ans = Math.max(ans, score); //최댓값 저장
	}	
}

 

outer라는 걸 처음 봤다. outer키워드를 적어주면 반복문을 여러 개 중첩시켰을 때 적어놓은 곳까지 break로 바로 빠져나올 수 있다. 너무나도 필요했던 기능....  아니 근데 백준이나 이클립스에서는 멀쩡한데 꼭 여기 붙이면 정렬이 코드 공백이 엉망이네...

 

perm 함수에서 순열을 돌려서 타자의 순서를 index로 저장해준다.

out 변수로 아웃을 체크하고 삼진아웃일 때마다 반복문을 빠져나와 이닝을 반복한다.

그리고 그 값을 계산을 통해 가장 최댓값을 구해준다.

 

주석이 친절해서 딱히 설명할 것이 없네...

 

 

 

 

 

반응형
myoskin