2013-02-24 09:17:19Morris
[UVA][dp][bitmask] 10149 - Yahtzee
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)
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
光是看懂計分方式就很浪費時間了。
"sum of all ones thrown" 這到底什麼意思呢?所有骰到點數 1 的總合,類推。
那這題要怎麼做呢?每種骰子只對應一種分類方式,組合就有 13!,又有特別的 bonus 分數計算,
當前六種分類方式總和 pt >= 63 額外加 35 分,問最高總分為多少?
為了加快速度,做法有點跟背包問題相似,逐步放入一骰子,然後進行狀態轉移。
在這裡必須將狀態壓縮,[0000000000010] // 代表第二個分類方式已經被使用。
然後記錄 dp[分類可使用的狀態][前六個分類的總分] = 最高分。
為什麼要多一個 [前六個分類的總分] 是因為到後面要計算 bonus 的時候要用的,
既然大於等於 63 都有 bonus,那麼記錄 0-63 個狀態就可以了。
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define STATE 8192 //1<<13
#define STATE2 64 // bonus use
#define DSIZE 13
int DICE[13][5];
int score_cat(int dice[], int cat) {
int tot = 0, i;
int D[7];
switch(cat) {
case 1:case 2:case 3:case 4:case 5:case 6:
for(i = 0; i < 5; i++)
if(dice[i] == cat)
tot += cat;
break;
case 7: // chance
for(i = 0; i < 5; i++)
tot += dice[i];
break;
case 8: // three of a kind
if(dice[0] == dice[2] || dice[1] == dice[3] ||
dice[2] == dice[4])
for(i = 0; i < 5; i++)
tot += dice[i];
break;
case 9: // four of a kind
if(dice[0] == dice[3] || dice[1] == dice[4])
for(i = 0; i < 5; i++)
tot += dice[i];
break;
case 10: // five of a kind
if(dice[0] == dice[4])
tot = 50;
break;
case 11: // short straight
for(i = 0; i <= 6; i++)
D[i] = 0;
for(i = 0; i < 5; i++)
D[dice[i]] = 1;
for(i = 1; i <= 3; i++) {
if(D[i] && D[i+1] && D[i+2] && D[i+3])
tot = 25;
}
break;
case 12: // long straight
for(i = 0; i < 4; i++) {
if(dice[i] != dice[i+1]-1)
return 0;
}
tot = 35;
break;
case 13: //full house
if(dice[0] == dice[1] && dice[2] == dice[4])
tot = 40;
if(dice[0] == dice[2] && dice[3] == dice[4])
tot = 40;
break;
}
return tot;
}
int count_bit(int n) {
static int i, j;
for(i = 0, j = 0; i < 13; i++)
j += (n>>i)&1;
return j;
}
int dp[STATE][STATE2]; // = max score
int score[DSIZE][DSIZE]; // score[i][j] = DICE[i] cat j
int arg_dp[STATE][STATE2][2]; //[0] category, [1] pre(1-6) total score
void sol_dp() {
int i, j, k, p, q;
for(i = 0; i < 13; i++)
for(j = 0; j < 13; j++)
score[i][j] = score_cat(DICE[i], j+1);
memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
int s, nstate, a, b;
for(k = 0; k < 13; k++) { // add DICE[k]
for(i = 0; i < STATE; i++) {// i = STATE mark
if(count_bit(i) == k) {
for(j = 0; j < 13; j++) {//set category
if(!((i>>j)&1)) {
s = score[k][j];
nstate = i|(1<<j); // new state
a = j < 6 ? s : 0;
for(p = 0; p < STATE2; p++) {
if(dp[i][p] >= 0) {
b = (p+a < 63) ? p+a : 63;
if(dp[nstate][b] < dp[i][p]+s) {
dp[nstate][b] = dp[i][p]+s;
arg_dp[nstate][b][0] = j;
arg_dp[nstate][b][1] = p;
}
}
}
}
}
}
}
}
int mx = 0, bouns = 0;
for(i = 0; i < 63; i++)
if(dp[STATE-1][i] > mx) {
mx = dp[STATE-1][i];
b = i;
}
if(dp[STATE-1][63] >= 0 && dp[STATE-1][63]+35 > mx) {
mx = dp[STATE-1][63]+35;
b = 63;
bouns = 35;
}
// backtracking
int category[13], state = STATE-1;
int ans[13];
for(i = 12; i >= 0; i--) {
category[i] = arg_dp[state][b][0];
b = arg_dp[state][b][1];
state ^= 1<<category[i];
ans[category[i]] = score[i][category[i]];
}
for(i = 0; i < 13; i++)
printf("%d ", ans[i]);
printf("%d %d\n", bouns, mx);
}
int main() {
int i, j;
while(1) {
for(i = 0; i < 13; i++) {
for(j = 0; j < 5; j++) {
if(scanf("%d", &DICE[i][j]) != 1)
return 0;
}
sort(DICE[i], DICE[i]+5);
}
//puts("==== START");
sol_dp();
}
return 0;
}