문제 풀이/[JAVA_자바] 백준

[JAVA / 자바] 백준 2798번 - 블랙잭

Seunghyun_KO 2022. 1. 5. 09:00
728x90
반응형

문제

카지노에서 제일 인기 있는 게임 블랙잭의 규칙은 상당히 쉽다. 카드의 합이 21을 넘지 않는 한도 내에서, 카드의 합을 최대한 크게 만드는 게임이다. 블랙잭은 카지노마다 다양한 규정이 있다.

한국 최고의 블랙잭 고수 김정인은 새로운 블랙잭 규칙을 만들어 상근, 창영이와 게임하려고 한다.

김정인 버전의 블랙잭에서 각 카드에는 양의 정수가 쓰여 있다. 그다음, 딜러는 N장의 카드를 모두 숫자가 보이도록 바닥에 놓는다. 그런 후에 딜러는 숫자 M을 크게 외친다.

이제 플레이어는 제한된 시간 안에 N장의 카드 중에서 3장의 카드를 골라야 한다. 블랙잭 변형 게임이기 때문에, 플레이어가 고른 카드의 합은 M을 넘지 않으면서 M과 최대한 가깝게 만들어야 한다.

N장의 카드에 써져 있는 숫자가 주어졌을 때, M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 구해 출력하시오.


입력

첫째 줄에 카드의 개수 N(3 ≤ N ≤ 100)과 M(10 ≤ M ≤ 300,000)이 주어진다. 둘째 줄에는 카드에 쓰여 있는 수가 주어지며, 이 값은 100,000을 넘지 않는 양의 정수이다.

합이 M을 넘지 않는 카드 3장을 찾을 수 있는 경우만 입력으로 주어진다.


출력

첫째 줄에 M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 출력한다.


 


문제 접근 방법

N개의 카드가 입력으로 주어지고 카드 3장을 골라 그 합이 입력된 목표합과 최대한 가까운 수를 출력해내면 된다.

이 경우 단순하게 생각해서 모든 경우를 계산해주면 된다.


JAVA 코드 풀이

- Scanner

import java.util.*;

public class Main {
    static int result = 0, cN = 0, tot = 0, card[];
    public static void main(String args[]) {
        Scanner input = new Scanner(System.in);
        cN = input.nextInt();
        tot = input.nextInt();
        card = new int[cN];
        while(cN-- > 0)
            card[cN] = input.nextInt();
        blackJack(0, 0, 0);
        System.out.println(result);
    }
    static void blackJack(int idx, int cnt, int sum) {
        if(sum <= tot) {
            if (cnt == 3)
                result = Math.max(result, sum);
            else
                for(int i=idx; i<card.length; i++)
                    blackJack(i+1, cnt+1, sum+card[i]);
        }
    }
}

 

- BufferedReader

import java.util.*;
import java.io.*;

public class Main {
    static int result = 0, cN = 0, tot = 0, card[];
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer init = new StringTokenizer(br.readLine());
        cN = Integer.parseInt(init.nextToken());
        tot = Integer.parseInt(init.nextToken());
        card = new int[cN];
        StringTokenizer st = new StringTokenizer(br.readLine());
        while(cN-- > 0)
            card[cN] = Integer.parseInt(st.nextToken());
        blackJack(0, 0, 0);
        System.out.println(result);
    }
    static void blackJack(int idx, int cnt, int sum) {
        if(sum <= tot) {
            if (cnt == 3)
                result = Math.max(result, sum);
            else
                for(int i=idx; i<card.length; i++)
                    blackJack(i+1, cnt+1, sum+card[i]);
        }
    }
}

코드 실행 결과

Scanner 코드 실행 결과
BufferedReader 코드 실행 결과


후기

처음 문제를 풀었을 땐 for문을 연속해서 써줌으로 조금 코드가 난잡했었다. 그래서 리뷰는 함수로 캡슐화시켜 코드의 재사용을 막고 가독성을 올리고, 입력받는 함수를 바꿔 성능면에서도 개선을 노력했다.

// 최초 문제 풀 때 작성한 코드

import java.util.*;

public class Main {
    public static void main(String args[]) {
        Scanner input = new Scanner(System.in);
        int cN = input.nextInt();
        int tot = input.nextInt();
        int card[] = new int[cN];
        while(cN-- > 0){
            card[cN] = input.nextInt();
        }
        int sum = 0, result = 0;
        for(int i=0; i<card.length; i++){
            sum += card[i];
            for(int j=i+1; j<card.length; j++){
                sum += card[j];
                for(int k=j+1; k<card.length; k++){
                    sum += card[k];
                    if(sum <= tot){
                        result = Math.max(result, sum);
                    }
                    sum -= card[k];
                }
                sum -= card[j];
            }
            sum -= card[i];
        }
        System.out.println(result);
    }
}

나 스스로 코드 리뷰를 하면서 반복되는 코드를 없애고, 불필요한 문장을 지우고, 가독성을 올려주고, 입력량이 많으면 scanner함수와 bufferedreader함수의 성능 비교도 해보고 그러면서 처음 문제를 풀 때는 보지 못했던 부분을 보면서 코드를 개선해가고 앞으로 풀 문제들을 보다 효율적이고 더 나은 코드로 만드려고 노력하는 중이다.

너무 처음부터 좋은 코드, 클린 코드(?)를 짜려고만 생각하다 보면 내 논리가 꼬이고 오히려 문제가 원래 난이도보다 어려워지는 경험을 많이 하고 있다. 브루트 포스 알고리즘으로 풀면 간단한 문제를 꼭 필요한 연산만 하려다 보니 그런 착오가 많이 생기는 중이다. 앞으로 더 많은 문제를 풀고 내가 짠 코드를 다시 살펴보면서 경험을 쌓고 실력을 키워 나가야겠다.


문제 원본

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

728x90
반응형