{ }codelper
枚举多重条件计数P0198

五个骰子的牌型

在骰子游戏中,每人把五个骰子(点数 1 到 6)掷一次。
掷出的五个点数的牌型,是下面八种牌型中符合的那些里最靠上的一种。
越靠上的牌型越强。
- FIVE:五个骰子点数全部相同 - FOUR:四个骰子点数相同 - FULLHOUSE:三个骰子点数相同,另外两个是与之不同的相同点数 - STRAIGHT:五个点数是 1 2 3 4 5 或 2 3 4 5 6(顺序不限) - TRIPLE:三个骰子点数相同,另外两个既与它不同、彼此也不同 - TWOPAIR:有两种不同的点数各出现两次 - PAIR:只有一对点数相同的骰子 - NOTHING:其余所有情况 第一行给出人数 n,接下来 n 行每行给出一个人掷出的五个点数,用空格分隔。
人的编号从 1 开始依次排列。
按一行一个,用大写输出每个人的牌型名称。
最后一行输出获胜者的编号。
牌型最强的人获胜;牌型相同时,五个点数之和大的人获胜。
仍然相同时,编号小的人获胜。
试着把牌型写成从弱到强、有八个值的枚举(enum),并用枚举值的大小来比较牌型。

输入
1 ≤ n ≤ 1,000,骰子点数是 1 到 6 的整数
输出
n+1 行:每个人的牌型名称,最后一行是获胜者的编号
样例 1 · stdin
5
3 3 3 5 5
2 4 3 6 5
6 2 6 2 3
5 5 3 3 3
1 2 3 4 6
stdout
FULLHOUSE
STRAIGHT
TWOPAIR
FULLHOUSE
NOTHING
1
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 6 种语言题解

这道题只接受有枚举的 Python、TypeScript、Java、C#、C、C++。
JavaScript 没有枚举语法,Craykon 也没有。
从弱到强声明牌型,值的大小就是强弱,于是“是否更强”只用一个 > 就能判断,但按大小比较枚举的方法各语言不同。
Python 普通的 Enum 不支持 <、>,会抛出 TypeError。
要写成 IntEnum 或者比较 .value。
TypeScript 数字 enum 和 C# enum 可以直接用 > 比较,C++ enum class 在同类型之间也能用 <、>(只有和整数混用时才需要 static_cast)。
Java 的 enum 不能用 >,要用按声明顺序(ordinal())比较的 compareTo。
C 的 enum 只是有名字的 int 常量,直接用 > 比较即可。
输出名称的方法也不同:Python h.name,TS 反向映射 Hand[h],Java toString(),C# ToString().ToUpperInvariant()(把声明的 FullHouse 转成大写),C 用名称表数组,C++ 用 switch 返回名称。
五个陷阱:① 直接 print(h) 输出 Python IntEnum 的值,从 3.11 起得到的是 5 这样的数而不是名称(普通 Enum 得到 Hand.FULLHOUSE)。
② 对普通 Enum 用 >,运行时会因 TypeError 停止。
③ 要从最强的牌型往下判断。
如果先问“是否有三个相同”再问葫芦,3 3 3 5 5 会变成 TRIPLE。
④ 只靠“最大点数 - 最小点数 == 4”并不是顺子,因为 1 1 1 3 5 也满足。
五个点数必须全都不同(这时只有缺的点数是 1 或 6 才连续)。
⑤ 牌型和点数和都相同时前面的人获胜,所以只在 > 时替换,不能用 >=。
另外,如果枚举是从强到弱声明的(FIVE 为 0),比较方向也必须反过来。

Pythonmain.py · 48 行
import sysfrom collections import Counterfrom enum import IntEnum  class Hand(IntEnum):    # 약한 것부터 적어서 값이 클수록 센 족보가 된다(IntEnum이라 > 로 비교할 수 있다)    NOTHING = 0    PAIR = 1    TWOPAIR = 2    TRIPLE = 3    STRAIGHT = 4    FULLHOUSE = 5    FOUR = 6    FIVE = 7  def classify(dice):    counts = sorted(Counter(dice).values(), reverse=True)  # 같은 눈이 몇 개씩인가, 많은 것부터    if counts[0] == 5:        return Hand.FIVE    if counts[0] == 4:        return Hand.FOUR    if counts == [3, 2]:        return Hand.FULLHOUSE    if sorted(dice) in ([1, 2, 3, 4, 5], [2, 3, 4, 5, 6]):        return Hand.STRAIGHT    if counts[0] == 3:        return Hand.TRIPLE    if counts == [2, 2, 1]:        return Hand.TWOPAIR    if counts[0] == 2:        return Hand.PAIR    return Hand.NOTHING  lines = sys.stdin.read().split("\n")n = int(lines[0])best = None  # (족보, 합, 번호)out = []for i in range(1, n + 1):    dice = list(map(int, lines[i].split()))    h = classify(dice)    out.append(h.name)  # print(h)는 IntEnum이라 "7"처럼 수가 나온다    if best is None or (h, sum(dice)) > (best[0], best[1]):        best = (h, sum(dice), i)out.append(str(best[2]))print("\n".join(out))
TypeScriptmain.ts · 48 行
import { readFileSync } from "node:fs"; // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand {  NOTHING,  PAIR,  TWOPAIR,  TRIPLE,  STRAIGHT,  FULLHOUSE,  FOUR,  FIVE,} function classify(dice: number[]): Hand {  const cnt: number[] = new Array<number>(7).fill(0); // cnt[눈] = 그 눈이 나온 주사위 수  for (const d of dice) cnt[d]++;  const most = Math.max(...cnt);  const pairs = cnt.filter((c) => c === 2).length;  const triple = cnt.includes(3);  if (most === 5) return Hand.FIVE;  if (most === 4) return Hand.FOUR;  if (triple && pairs === 1) return Hand.FULLHOUSE;  // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다  if (most === 1 && (cnt[1] === 0 || cnt[6] === 0)) return Hand.STRAIGHT;  if (triple) return Hand.TRIPLE;  if (pairs === 2) return Hand.TWOPAIR;  if (pairs === 1) return Hand.PAIR;  return Hand.NOTHING;} const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const out: string[] = [];let bestHand = Hand.NOTHING, bestSum = -1, winner = 0;for (let i = 1; i <= n; i++) {  const dice = lines[i].trim().split(/\s+/).map(Number);  const h = classify(dice);  const sum = dice.reduce((a, b) => a + b, 0);  out.push(Hand[h]); // h는 수라서 이름은 역방향 표 Hand[h]로 꺼낸다  if (h > bestHand || (h === bestHand && sum > bestSum)) {    bestHand = h;    bestSum = sum;    winner = i;  }}out.push(String(winner));console.log(out.join("\n"));
JavaMain.java · 55 行
import java.io.*;import java.util.*; public class Main {    // 약한 것부터 적으면 선언 차례(ordinal)가 곧 세기 차례다    enum Hand { NOTHING, PAIR, TWOPAIR, TRIPLE, STRAIGHT, FULLHOUSE, FOUR, FIVE }     static Hand classify(int[] dice) {        int[] cnt = new int[7]; // cnt[눈] = 그 눈이 나온 주사위 수        for (int d : dice) cnt[d]++;        int most = 0, pairs = 0;        boolean triple = false;        for (int c : cnt) {            most = Math.max(most, c);            if (c == 2) pairs++;            if (c == 3) triple = true;        }        if (most == 5) return Hand.FIVE;        if (most == 4) return Hand.FOUR;        if (triple && pairs == 1) return Hand.FULLHOUSE;        // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다        if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand.STRAIGHT;        if (triple) return Hand.TRIPLE;        if (pairs == 2) return Hand.TWOPAIR;        if (pairs == 1) return Hand.PAIR;        return Hand.NOTHING;    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder sb = new StringBuilder();        Hand bestHand = null;        int bestSum = -1, winner = 0;        for (int i = 1; i <= n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            int[] dice = new int[5];            int sum = 0;            for (int k = 0; k < 5; k++) {                dice[k] = Integer.parseInt(st.nextToken());                sum += dice[k];            }            Hand h = classify(dice);            sb.append(h).append('\n'); // enum의 toString()은 이름            // enum의 compareTo는 선언 차례로 비교한다            if (bestHand == null || h.compareTo(bestHand) > 0 || (h == bestHand && sum > bestSum)) {                bestHand = h;                bestSum = sum;                winner = i;            }        }        sb.append(winner).append('\n');        System.out.print(sb);    }}
C#Main.cs · 50 行
using System;using System.Linq;using System.Text; // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand { Nothing, Pair, TwoPair, Triple, Straight, FullHouse, Four, Five } class Program{    static Hand Classify(int[] dice)    {        var cnt = new int[7]; // cnt[눈] = 그 눈이 나온 주사위 수        foreach (int d in dice) cnt[d]++;        int most = cnt.Max();        int pairs = cnt.Count(c => c == 2);        bool triple = cnt.Contains(3);        if (most == 5) return Hand.Five;        if (most == 4) return Hand.Four;        if (triple && pairs == 1) return Hand.FullHouse;        // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다        if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand.Straight;        if (triple) return Hand.Triple;        if (pairs == 2) return Hand.TwoPair;        if (pairs == 1) return Hand.Pair;        return Hand.Nothing;    }     static void Main()    {        int n = int.Parse(Console.ReadLine()!.Trim());        var sb = new StringBuilder();        Hand bestHand = Hand.Nothing;        int bestSum = -1, winner = 0;        for (int i = 1; i <= n; i++)        {            int[] dice = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();            Hand h = Classify(dice);            int sum = dice.Sum();            sb.Append(h.ToString().ToUpperInvariant()).Append('\n'); // ToString()은 "FullHouse"            if (h > bestHand || (h == bestHand && sum > bestSum))            {                bestHand = h;                bestSum = sum;                winner = i;            }        }        sb.Append(winner).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 63 行
#include <algorithm>#include <array>#include <iostream>#include <string> // 약한 것부터 적으면 선언 차례가 곧 세기 차례다. enum class끼리는 < > 로 바로 비교된다enum class Hand { Nothing, Pair, TwoPair, Triple, Straight, FullHouse, Four, Five }; // enum class는 자기 이름을 모르니 switch로 돌려준다std::string name(Hand h) {    switch (h) {        case Hand::Nothing: return "NOTHING";        case Hand::Pair: return "PAIR";        case Hand::TwoPair: return "TWOPAIR";        case Hand::Triple: return "TRIPLE";        case Hand::Straight: return "STRAIGHT";        case Hand::FullHouse: return "FULLHOUSE";        case Hand::Four: return "FOUR";        case Hand::Five: return "FIVE";    }    return "";} Hand classify(const std::array<int, 5>& dice) {    std::array<int, 7> cnt{}; // cnt[눈] = 그 눈이 나온 주사위 수    for (int d : dice) cnt[d]++;    int most = *std::max_element(cnt.begin(), cnt.end());    int pairs = std::count(cnt.begin(), cnt.end(), 2);    bool triple = std::count(cnt.begin(), cnt.end(), 3) > 0;    if (most == 5) return Hand::Five;    if (most == 4) return Hand::Four;    if (triple && pairs == 1) return Hand::FullHouse;    // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다    if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand::Straight;    if (triple) return Hand::Triple;    if (pairs == 2) return Hand::TwoPair;    if (pairs == 1) return Hand::Pair;    return Hand::Nothing;} int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    Hand bestHand = Hand::Nothing;    int bestSum = -1, winner = 0;    for (int i = 1; i <= n; i++) {        std::array<int, 5> dice;        int sum = 0;        for (int& d : dice) {            std::cin >> d;            sum += d;        }        Hand h = classify(dice);        std::cout << name(h) << "\n";        if (h > bestHand || (h == bestHand && sum > bestSum)) {            bestHand = h;            bestSum = sum;            winner = i;        }    }    std::cout << winner << "\n";}
Cmain.c · 51 行
#include <stdbool.h>#include <stdio.h> // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand { NOTHING, PAIR, TWOPAIR, TRIPLE, STRAIGHT, FULLHOUSE, FOUR, FIVE };// C의 enum은 이름을 모르는 int 상수라서 이름표를 따로 둔다(차례를 enum과 똑같이)static const char *NAME[] = {"NOTHING", "PAIR", "TWOPAIR", "TRIPLE", "STRAIGHT", "FULLHOUSE", "FOUR", "FIVE"}; enum Hand classify(const int dice[5]) {    int cnt[7] = {0}; // cnt[눈] = 그 눈이 나온 주사위 수    for (int k = 0; k < 5; k++) cnt[dice[k]]++;    int most = 0, pairs = 0;    bool triple = false;    for (int v = 1; v <= 6; v++) {        if (cnt[v] > most) most = cnt[v];        if (cnt[v] == 2) pairs++;        if (cnt[v] == 3) triple = true;    }    if (most == 5) return FIVE;    if (most == 4) return FOUR;    if (triple && pairs == 1) return FULLHOUSE;    // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다    if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return STRAIGHT;    if (triple) return TRIPLE;    if (pairs == 2) return TWOPAIR;    if (pairs == 1) return PAIR;    return NOTHING;} int main(void) {    int n;    scanf("%d", &n);    enum Hand best_hand = NOTHING;    int best_sum = -1, winner = 0;    for (int i = 1; i <= n; i++) {        int dice[5], sum = 0;        for (int k = 0; k < 5; k++) {            scanf("%d", &dice[k]);            sum += dice[k];        }        enum Hand h = classify(dice);        puts(NAME[h]);        if (h > best_hand || (h == best_hand && sum > best_sum)) {            best_hand = h;            best_sum = sum;            winner = i;        }    }    printf("%d\n", winner);    return 0;}