uva 10149 - Yahtzee(DP)

本文介绍了一种计算Yahtzee游戏最佳可能得分的算法实现。通过动态规划方法,文章详细展示了如何针对每轮投掷的五枚骰子,在13种计分类别中选择最优得分策略,同时考虑了额外的奖励分数条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem A - Yahtzee

The game of Yahtzee involves 5 dice, which are thrown in 13 rounds. A score card contains 13 categories; each round may be scored in a category of the player's choosing, but each category may be scored only once in the game. The 13 categores are scored as follows:
  • ones - sum of all ones thrown
  • twos - sum of all twos thrown
  • threes - sum of all threes thrown
  • fours - sum of all fours thrown
  • fives - sum of all fives thrown
  • sixes - sum of all sixes thrown

  • chance - sum of all dice

  • three of a kind - sum of all dice, provided at least three have same value
  • four of a kind - sum of all dice, provided at least four have same value
  • five of a kind - 50 points, provided all five dice have same value
  • short straight - 25 points, provided four of the dice form a sequence (that is, 1,2,3,4 or 2,3,4,5 or 3,4,5,6)
  • long straight - 35 points, provided all dice form a sequence (1,2,3,4,5 or 2,3,4,5,6)
  • full house - 40 points, provided three of the dice are equal and the other two dice are also equal. (for example, 2,2,5,5,5)
Each of the last six categories may be scored as 0 if the criteria are not met.

The score for the game is the sum of all 13 categories plus a bonus of 35 points if the sum of the first six categores (ones to sixes) is 63 or greater.

Your job is to compute the best possible score for a sequence of rounds.

The Input

Each line of input contains 5 integers between 1 and 6, indicating the values of the five dice thrown in each round. There are 13 such lines for each game, and there may be any number of games in the input data.

The Output

Your output should consist of a single line for each game containing 15 numbers: the score in each category (in the order given), the bonus score (0 or 35), and the total score. If there is more than categorization that yields the same total score, any one will do.

Sample Input

1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 1 1 1 1
6 6 6 6 6
6 6 6 1 1
1 1 1 2 2
1 1 1 2 3
1 2 3 4 5
1 2 3 4 6
6 1 2 6 6
1 4 5 5 5
5 5 5 5 6
4 4 4 5 6
3 1 3 6 3
2 2 2 4 6

Output for Sample Input

1 2 3 4 5 0 15 0 0 0 25 35 0 0 90
3 6 9 12 15 30 21 20 26 50 25 35 40 35 327

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 10000;
int dp[maxn] , sum[maxn][20] , bonues , total , dice[20][5];

void initial(){
    for(int i = 0; i < maxn; i++){
        dp[i] = -1;
    }
    memset(sum , 0 , sizeof sum);
    total = 0;
    bonues = 0;
}

void readcase(){
    for(int i = 1; i < 13; i++){
        for(int j = 0; j < 5; j++){
            scanf("%d" , &dice[i][j]);
        }
    }
}

int get_sum(int k , int d){
    k++;
    int t = 0 , appear[8] = {0};
    if(k <= 6){
        for(int i = 0; i < 5; i++){
            if(dice[d][i] == k) t += k;
        }
        return t;
    }
    for(int i = 0; i < 5; i++){
        t += dice[d][i];
        appear[dice[d][i]]++;
    }
    if(k == 7){
        return t;
    }
    if(k == 8 || k == 9){
        for(int i = 1; i < 7; i++){
            if(appear[i] >= k-5) return t;
        }
        return 0;
    }
    if(k == 10){
        for(int i = 1; i < 7; i++){
            if(appear[i] >= 5) return 50;
        }
        return 0;
    }
    if(k == 11){
        if(appear[1] && appear[2] && appear[3] && appear[4]) return 25;
        if(appear[5] && appear[2] && appear[3] && appear[4]) return 25;
        if(appear[5] && appear[6] && appear[3] && appear[4]) return 25;
        return 0;
    }
    if(k == 12){
        if(appear[1] && appear[2] && appear[3] && appear[4] && appear[5]) return 35;
        if(appear[6] && appear[2] && appear[3] && appear[4] && appear[5]) return 35;
        return 0;
    }
    if(k == 13){
        for(int i = 1; i < 7; i++){
            if(appear[i] == 3){
                for(int j = 1; j < 7; j++){
                    if(appear[j] == 2){
                        return 40;
                    }
                }
            }
        }
        return 0;
    }
    return 0;
}

int DP(int k , int category){
    if(k < 0) return 0;
    if(dp[category] != -1) return dp[category];
    int ans = 0;
    for(int i = 0; i < 13; i++){
        if(category&(1<<i)){
            int tsum = get_sum(k , i);
            if(ans < tsum+DP(k-1 , category-(1<<i))){
                ans = tsum+DP(k-1 , category-(1<<i));
                sum[category][k] = i;
            }
        }
    }
    if(k == 5 && ans >= 63){
        ans += 35;
    }
    return dp[category] = ans;
}

void output(int k , int category){
    if(k == 0){
        printf("%d " , get_sum(k , sum[category][k]));
        return;
    }
    output(k-1 , category-(1<<sum[category][k]));
    printf("%d " , get_sum(k , sum[category][k]));
    if(k == 5 && DP(k , category) >= 63) bonues = 35;
}

void computing(){
    int category = 0;
    for(int i = 0; i < 13; i++){
        category += (1<<i);
    }
    total = DP(12 , category);
    output(12 , category);
    printf("%d %d\n" , bonues , total);
}

int main(){
    while(scanf("%d%d%d%d%d" , &dice[0][0], &dice[0][1], &dice[0][2], &dice[0][3], &dice[0][4]) != EOF){
        initial();
        readcase();
        computing();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值