#include <memory.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
class Calculator
{
public:
Calculator()
{
m_diceInTotalRounds.push_back(NULL);
}
~Calculator()
{
for (size_t i = 1; i < m_diceInTotalRounds.size(); ++i)
delete m_diceInTotalRounds[i];
}
void OutputResult()
{
int sum = 0, award = 0;
for (int i = 1; i <= AWARD_FUNC_CNT; ++i)
{
cout << m_result[i] << ' ';
sum += m_result[i];
}
if (sum >= AWARD_THRESHOLD)
award = AWARD_SCORE;
sum += award;
for (int i = AWARD_FUNC_CNT + 1; i <= CALC_FUNC_CNT; ++i)
{
cout << m_result[i] << ' ';
sum += m_result[i];
}
cout << award << ' ' << sum << endl;
}
bool Init()
{
static int dice[DICE_CNT];
for (int i = 1; i <= CALC_FUNC_CNT; ++i)
{
for (int j = 0; j < DICE_CNT; ++j)
{
if (!(cin >> dice[j]))
return false;
}
AddToDiceInTotalRounds(dice);
}
return true;
}
void Calculate()
{
CalcInit();
GetMaxScore(CALC_FUNC_CNT, s_calculatedRounds);
SetResult();
}
static const int CALC_FUNC_CNT = 13;
static const int DICE_CNT = 5;
private:
int GetIndexOfToCalculatedRounds(bool* calculatedRounds)
{
int sum = 0, multiplyer = 1;
for (int i = 1; i <= CALC_FUNC_CNT; ++i, multiplyer <<= 1)
{
if (!calculatedRounds[i])
sum += multiplyer;
}
return sum;
}
int GetAppliedRoundOfMaxScore(int calcFunc, bool* calculatedRounds)
{
return s_TotalRoundsDiceScoreInfo[calcFunc][GetIndexOfToCalculatedRounds(calculatedRounds)].m_appliedRound;
}
void SetResult()
{
memset(s_calculatedRounds, 0, sizeof(s_calculatedRounds));
for (int i = CALC_FUNC_CNT; i >= 1; --i)
{
int selectedRound = GetAppliedRoundOfMaxScore(i, s_calculatedRounds);
s_calculatedRounds[selectedRound] = true;
m_result[i] = s_SingleRoundDiceScore[i][selectedRound];
}
}
void CalcInit()
{
InitSingleRoundDiceScore();
InitTotalRoundsDiceScore();
memset(s_calculatedRounds, 0, sizeof(s_calculatedRounds));
}
int GetMaxScore(int curCalcFunc, bool* calculatedRounds)
{
int index = GetIndexOfToCalculatedRounds(calculatedRounds);
int existingMax = s_TotalRoundsDiceScoreInfo[curCalcFunc][index].m_maxScore;
if (existingMax >= 0)
return existingMax;
int max = -1, selectedRound = 0;
for (int i = 1; i <= CALC_FUNC_CNT; ++i)
{
if (calculatedRounds[i])
continue;
int curResult;
if (curCalcFunc == 1)
curResult = s_SingleRoundDiceScore[curCalcFunc][i];
else
{
calculatedRounds[i] = true;
curResult = s_SingleRoundDiceScore[curCalcFunc][i] + GetMaxScore(curCalcFunc - 1, calculatedRounds);
calculatedRounds[i] = false;
}
if (curResult > max)
{
max = curResult;
selectedRound = i;
}
}
if ((curCalcFunc == AWARD_FUNC_CNT) && (max >= AWARD_THRESHOLD))
max += AWARD_SCORE;
s_TotalRoundsDiceScoreInfo[curCalcFunc][index].m_maxScore = max;
s_TotalRoundsDiceScoreInfo[curCalcFunc][index].m_appliedRound = selectedRound;
return max;
}
void InitTotalRoundsDiceScore()
{
memset(s_TotalRoundsDiceScoreInfo, 0xFF /*-1*/, sizeof(s_TotalRoundsDiceScoreInfo));
}
void InitSingleRoundDiceScore()
{
for (int i = 1; i <= CALC_FUNC_CNT; ++i)
{
for (int j = 1; j <= CALC_FUNC_CNT; ++j)
s_SingleRoundDiceScore[i][j] = s_CalcFuncs[i](*(m_diceInTotalRounds[j]));
}
}
void AddToDiceInTotalRounds(int* dice)
{
m_diceInTotalRounds.push_back(new SortedDiceInRound());
int cnt = m_diceInTotalRounds.size();
for (int i = 0; i < DICE_CNT; ++i)
m_diceInTotalRounds[cnt - 1]->push_back(dice[i]);
sort(m_diceInTotalRounds[cnt - 1]->begin(), m_diceInTotalRounds[cnt - 1]->end());
}
typedef vector<int> SortedDiceInRound;
// Calculation Functions Begin
template <int N>
static int Count(const SortedDiceInRound& sortedDiceInRound)
{
int sum = 0;
for (int i = 0; i < DICE_CNT; ++i)
{
if (sortedDiceInRound[i] == N)
sum += N;
else if (sortedDiceInRound[i] > N)
break;
}
return sum;
}
static int Sum(const SortedDiceInRound& sortedDiceInRound)
{
int sum = 0;
for (int i = 0; i < DICE_CNT; ++i)
sum += sortedDiceInRound[i];
return sum;
}
static int Same3(const SortedDiceInRound& sortedDiceInRound)
{
if ((sortedDiceInRound[0] == sortedDiceInRound[2]) ||
(sortedDiceInRound[1] == sortedDiceInRound[3]) ||
(sortedDiceInRound[2] == sortedDiceInRound[4]))
return Sum(sortedDiceInRound);
return 0;
}
static int Same4(const SortedDiceInRound& sortedDiceInRound)
{
if ((sortedDiceInRound[0] == sortedDiceInRound[3]) ||
(sortedDiceInRound[1] == sortedDiceInRound[4]))
return Sum(sortedDiceInRound);
return 0;
}
static int Same5(const SortedDiceInRound& sortedDiceInRound)
{
if (sortedDiceInRound[0] == sortedDiceInRound[4])
return 50;
return 0;
}
static int SmallSeq(const SortedDiceInRound& sortedDiceInRound)
{
set<int> seqSet;
for (int i = 0; i < DICE_CNT; ++i)
seqSet.insert(sortedDiceInRound[i]);
if (seqSet.size() < 4)
return 0;
if ((seqSet.find(3) == seqSet.end()) || (seqSet.find(4) == seqSet.end()))
return 0;
if ((seqSet.find(1) != seqSet.end()) && (seqSet.find(2) != seqSet.end()))
return 25;
if ((seqSet.find(2) != seqSet.end()) && (seqSet.find(5) != seqSet.end()))
return 25;
if ((seqSet.find(5) != seqSet.end()) && (seqSet.find(6) != seqSet.end()))
return 25;
return 0;
}
static int BigSeq(const SortedDiceInRound& sortedDiceInRound)
{
if ((sortedDiceInRound[0] == 1) &&
(sortedDiceInRound[4] == 5) &&
(sortedDiceInRound[1] == 2) &&
(sortedDiceInRound[2] == 3) &&
(sortedDiceInRound[3] == 4))
return 35;
if ((sortedDiceInRound[0] == 2) &&
(sortedDiceInRound[4] == 6) &&
(sortedDiceInRound[1] == 3) &&
(sortedDiceInRound[2] == 4) &&
(sortedDiceInRound[3] == 5))
return 35;
return 0;
}
static int Calabash(const SortedDiceInRound& sortedDiceInRound)
{
if ((sortedDiceInRound[0] == sortedDiceInRound[2]) && (sortedDiceInRound[3] == sortedDiceInRound[4]))
return 40;
if ((sortedDiceInRound[2] == sortedDiceInRound[4]) && (sortedDiceInRound[0] == sortedDiceInRound[1]))
return 40;
return 0;
}
// Calculation Functions End
private:
static const int DIM_CNT = ((1 << CALC_FUNC_CNT) - 1);
static const int AWARD_FUNC_CNT = 6;
static const int AWARD_THRESHOLD = 63;
static const int AWARD_SCORE = 35;
static bool s_calculatedRounds[CALC_FUNC_CNT + 1];
typedef int (*PCALC_FUNC)(const SortedDiceInRound& sortedDiceInRound);
const static PCALC_FUNC s_CalcFuncs[CALC_FUNC_CNT + 1];
/* Structure of s_SingleRoundDiceScore
Methods | Round1 | Round2 | ... | Round13 |
-----------------------------------------------
Method1 | x1,1 | x1,2 | ... | x1,13 |
Method2 | x1,1 | x1,2 | ... | x1,13 |
... | ... | ... | ... | ... |
Method13 | x13,1 | x13,2 | ... | x13,13 |
*/
static int s_SingleRoundDiceScore[CALC_FUNC_CNT + 1][CALC_FUNC_CNT + 1];
struct ScoreInfo
{
int m_maxScore;
int m_appliedRound;
};
static ScoreInfo s_TotalRoundsDiceScoreInfo[CALC_FUNC_CNT + 1][DIM_CNT + 1];
vector<SortedDiceInRound*> m_diceInTotalRounds;
int m_result[CALC_FUNC_CNT + 1]; // Store the score for each calculation function.
};
int Calculator::s_SingleRoundDiceScore[CALC_FUNC_CNT + 1][CALC_FUNC_CNT + 1];
Calculator::ScoreInfo Calculator::s_TotalRoundsDiceScoreInfo[CALC_FUNC_CNT + 1][DIM_CNT + 1];
bool Calculator::s_calculatedRounds[Calculator::CALC_FUNC_CNT + 1];
const Calculator::PCALC_FUNC Calculator::s_CalcFuncs[] = {
NULL,
Calculator::Count<1>,
Calculator::Count<2>,
Calculator::Count<3>,
Calculator::Count<4>,
Calculator::Count<5>,
Calculator::Count<6>,
Calculator::Sum,
Calculator::Same3,
Calculator::Same4,
Calculator::Same5,
Calculator::SmallSeq,
Calculator::BigSeq,
Calculator::Calabash
};
void DoTest()
{
while(true)
{
Calculator calc;
if (!calc.Init())
return;
calc.Calculate();
calc.OutputResult();
}
}
int main(int argc, char* argv[])
{
DoTest();
return 0;
}