출처: [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장을 뽑는 경우의 수 = 52C5 = 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 |
댓글