본문 바로가기
PS 문제 풀이/SWEA

[SWEA] 3996 Poker

by 까망 하르방 2021. 3. 1.
반응형

출처: [SWEA] SW 문제해결 심화 - Counting & Probability

 Input 

1

S 1

S 10

D 11

H 10

C 2

H 2

S 11

 

 Output 

#1 2 Pair

 

Poker 카드 7장 중에서 5장을 선택합니다.

해당 문제에서 카드의 족보는 다음과 같습니다. (번호가 높으수록 높은 등급)

(0) Top : 가장 낮은 족보

(1) 1 Pair : 같은 숫자가 한 쌍 존재

(2) 2 Pair : 각기 같은 숫자가 두 쌍 존재

(3) Triple : 세 개의 같은 숫자가 존재

(4) Straight : 숫자 5개가 연속 존재

(5) Flush : 같은 무늬 5장이 존재

(6) Full House : Triple과 Pair가 함께 존재

(7) 4 Card : 네 개의 같은 숫자가 존재

(8) Straight Flush : 같은 무늬의 연속된 숫자 5개가 존재

※ 단, Ace(1)는 숫자 1 혹은 14로 사용될 수 있습니다.

     하지만, 연속된 숫자를 확인할 때 1과 14로 동시에 사용될 수 없음.

     ex) [Q, K, A, 2, 3]의 경우 Straight로 보지 않습니다. Ace가 1이면서 14여야 하기 때문.

 

 

카드는 4(모양) × 13(숫자) = 52장의 카드가 존재.

52장 중에 5장을 뽑는 경우의 수 = 52C= 2,598,960

실제 포커 족보는 아래와 같습니다.

(지역 혹은 규정에 따라 다를 수 있음)

 

① (중복 없는) 조합을 이용해 7장의 카드 중 5장에 대한 Case를 구합니다.

     → 7C5 = 7C2 = 21으로 Test Case 개수 T ≤ 20 이므로 TLE 발생 X

 

② 21가지 경우에 대해서 각각의 등급을 구합니다.

ex) 5장의 카드 = [(S 1) (S 10) (D 11) (H 10) (C 2)]

- Flush(같은 무늬 5장이 존재) 여부 확인

- Ace를 1과 14 동시에 count해서 Straight(숫자 5개 연속) 여부를 확인.

(5칸씩 Slide 하면서 모두 numbers[i] == 1인지 확인)

1~13까지 중 동일한 숫자가 몇 번씩 나왔는지 확인하여 

→ 1 Pair / 2 Pair / Triple / Full House 등급 확인

    ※ Full House의 경우 1 Pair + Triple 조합을 의미합니다.

③ 각 등급 중 가장 높은 등급을 출력합니다.


import java.io.*;
import java.util.*;
 
public class Solution {
    static final String[] GRADE_NAME = {"Top" ,"1 Pair" ,"2 Pair" ,"Triple" ,
            "Straight" ,"Flush" ,"Full House" ,"4 Card" ,"Straight Flush"};
    static boolean[] grade;
    static List<Card> deck;
     
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;
 
        int T = Integer.parseInt(br.readLine());
        for (int tc = 1; tc <= T; tc++) {
             
            // 7장의 카드 입력
            deck = new ArrayList<Card>();
            for(int i=0; i<7; i++) {
                st = new StringTokenizer(br.readLine());    
                String suit = st.nextToken();
                int number = Integer.parseInt(st.nextToken());
                deck.add(new Card(suit, number));
            }
             
            grade = new boolean[9]; 
            grade[0] = true; // 등급: Top
             
            // 조합을 이용해 7장 중에서 5장의 카드 선택
            List<Card> candidate = new ArrayList<Card>();
            combination(candidate, 0);
 
             
            System.out.print("#" + tc + " ");
            // 문제에서 제시한 8개의 등급 중 높은 등급 출력
            for(int i=8; i>=0; i--) {
                if(grade[i]) {
                    System.out.println(GRADE_NAME[i]);
                    break;
                }
            }
        }
    }
     
    private static void combination(List<Card> candidate, int idx) {
        // 카드 5장이 모두 선택된 경우
        if(candidate.size() == 5) {
            findGrade(candidate);
            return;
        }
         
        if(idx >= 7) { 
            return;
        }
         
        candidate.add(deck.get(idx));
        combination(candidate, idx + 1);
        candidate.remove(candidate.size()-1);
        combination(candidate, idx + 1);
    }
 
    private static void findGrade(List<Card> candidate) {
        // 카드 모양 1:S, 2:D, 3:C, 4:H  
        int[] suits = new int[5]; 
        int[] numbers = new int[15]; // 카드 숫자 1~14 (Ace의 경우 1, 14 동시 count)
        for(int i=0; i<5; i++) {
            Card card = candidate.get(i);
            // 카드 숫자에 따른 count
            numbers[card.number]++;
            // Ace의 경우 
            if(card.number == 1) numbers[14]++;
            // 카드 모양에 따른 count
            switch (card.suit) {
            case "S":
                suits[1]++;
                break;
            case "D":
                suits[2]++;
                break;
            case "C":
                suits[3]++;
                break;
            case "H":
                suits[4]++;
                break;
            }
        }
         
        // [4] Straight (숫자 5개가 연속 존재)
        boolean isStraight = false;
        // Ace를 1, 14로 처리해서 연속된 구간 확인
        for(int i=1; i<=10; i++){
            int temp = 0;
            // 5개의 연속 구간 확인
            for(int j=i; j<i+5; j++){
                if(numbers[j] != 1) break;
                temp++;
            }
            if(temp == 5) isStraight = true;
        }
        if(isStraight) grade[4] = true;
         
        // [5] Flush (같은 무늬 5장이 존재)
        boolean isFlush = false;
        for(int i=1; i<5; i++) {
            if(suits[i] == 5) isFlush = true;
        }
        if(isFlush) grade[5] = true;
         
        // [8] Straight Flush (같은 무늬의 연속된 숫자 5개가 존재)
        if(isFlush && isStraight) grade[8] = true;
         
        int pairCnt = 0;
        int tripleCnt = 0;
        // Ace를 1로 단일 숫자로 처리해서 확인 (14 의미 제외)
        for(int i=1; i<14; i++) {
            // [7] 4 Card (네 개의 같은 숫자가 존재)
            if(numbers[i] == 4) grade[7] = true;
 
            // 같은 숫자가 2개
            if(numbers[i] == 2) pairCnt++;
            // 같은 숫자가 3개
            else if(numbers[i] == 3) tripleCnt++;
        }
         
        // [1] 1 Pair (같은 숫자가 한 쌍 존재)
        if(pairCnt == 1) grade[1] = true;
        // [2] 2 Pair (각기 같은 숫자가 두 쌍 존재)
        if(pairCnt == 2) grade[2] = true;
        // [3] Triple (세 개의 같은 숫자가 존재)
        if(tripleCnt == 1) grade[3] = true;
        // [6] Full House (Triple과 Pair가 함께 존재)
        if(tripleCnt == 1 && pairCnt == 1) grade[6] = true;
    }
}
 
class Card {
    String suit;
    int number;
 
    Card(String suit, int number) {
        this.suit = suit;
        this.number = number;
    }
}

 

반응형

'PS 문제 풀이 > SWEA' 카테고리의 다른 글

[SWEA] 4040 문자열의 거듭제곱  (0) 2021.03.01
[SWEA] 1218 괄호 짝짓기  (0) 2021.03.01
[SWEA] 4041 Convex  (0) 2021.03.01
[SWEA] 3951 CRT  (0) 2021.03.01
[SWEA] 3993 Pole  (0) 2021.03.01

댓글