// Yahtzee (Yahtzee game) // PC/Ultraviolet IDs: 110208/10149, Popularity: C, Success rate: average Level: 3 // copyright ownership (C), Qiu, 2011. Metaphysis at yeah dot net // Verdict: Accepted // Submission Date: 2011-05-16 // ultraviolet A Run Time: 0.088 s // You can select any of the 13 scoring methods for each group of shards. The selected scoring method cannot be selected again. If each group of workers is scored based on each method and the scores are arranged as follows, a matrix is obtained. /// C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 // ------------------------------------------------ // R1 | a1 a2 a3 a4 a5 a7 a8 a9 a10 a11 a12 a13 // R2 | b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 // R3 | c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 // R4 | d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d12 d13 // R5 | e1 e2 e3 e5 e6 e7 e8 e9 e10 e11 e12 e13 // R6 | f1 f2 f3 f5 f6 f7 f8 f9 f10 f11 f12 f13 // R7 | G1 g2 g3 g4 g6 g7 g8 g9 g10 g11 g12 g13 // R8 | h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13 // R9 | i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 // R10 | j1 j2 j3 j4 j5 j6 j7 j8 j9 j10 j11 j12 j13 // R11 | k1 k2 k3 k4 k6 k7 k8 k9 k10 k11 k12 k13 // R12 | l1 l2 l3 l4 l5 l6 l7 l8 LAN l10 l11 l12 l13 // R13 | m 1 M2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 // ci (I = 1 ,.., 13) indicates the scoring type. Ri (I = 1,..., 13) indicates the number of groups. A1-a13 indicates the scores obtained by the first // group of workers based on various scoring methods, and the rest are similar. The requirements of a question can actually be converted into the following (not considering the bonus/bonus score for the moment): from the matrix of the 13 columns in the above 13 rows, each row and each column only take one number and add the obtained number to obtain the maximum value and method. There are multiple methods to obtain the maximum value and method. Intuitively, the first line can take 13 methods, the second line has 12 methods, similar to //, a total of 13! = 6227020800 methods. If the exhaustive algorithm is used, the maximum value can be found, but the program running // time exceeds the requirement. The exhaustive algorithm repeats computation multiple times during the computation process, which greatly increases the program running time. To improve the efficiency // rate, you must reduce the amount of repeated computation. People with algorithms should be aware that Dynamic planning should be used to solve the problem. //// The Yahtzee problem is actually a typical problem of applying dynamic planning algorithms. When applying dynamic planning, one technique is to use bitmask // (bitmask) to construct all combinations, as shown in the preceding example, there are a total of 2 ^ 13 = 8192 different combinations of the 13 scoring methods. For each combination, obtain the maximum value and obtain the result gradually. For the matrix given above, assuming that the first group of workers selects the first calculation method and the score is a1, the second group of workers can only choose one of the 2-13 scoring methods, how does one indicate this status? If the status of each score method is displayed as follows: /// C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 // 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 // when a scoring method used, in this scoring method, the value is 1. Otherwise, the value is 0. If the first group of consumers chooses the first scoring method, C1 is // 1. If the second group of consumers uses the second scoring method, C2 is 1, convert the status of 1 and 0 from C1 to C13 to 1 // binary number (C13 is at the beginning and C1 is at the end) to: // 0000000000011 (B) //// the binary number is 3 of the 10-digit number. On the contrary, the first group selects the second scoring method, and the second group selects the first scoring method. // The resulting binary number is still: // 0000000000011 (B) //// the status indicates that no matter the sequence of the first or second scoring method selected by the first group and the second group of workers, you only need to compare the two options with a higher score, in this case, we set up an array sum and use the binary number, namely, 3 in decimal format, as the serial number of the array, the array element // indicates the maximum value when the first and second groups use the first or second scoring method. Similarly, for the following binary numbers: // 0000000000101 (B) /// it indicates that the first group of shards and the third group each take the first or third scoring method, similarly, use the binary number 5 in decimal format as the array // serial number, and store the maximum value of the score and sum [5. Consider the status represented by the following binary numbers: // 0000000000111 (B) /// the first three scoring methods are selected for the first three groups of workers. This binary number may be 0000000000011 (B) and 0000000000100 (B) //, or 0000000000101 (B) and 0000000000010 (B, the meaning of the two operations. // The first and second groups obtain the maximum value obtained by the first and second scoring methods and the third group obtain the third scoring method // add to the value, the second indicates that the maximum value obtained by the first and third scoring methods is obtained from the first and third scoring methods, and the sum of the second score obtained by the second scoring method, if you compare the scores obtained by the two operations and store the values in the binary number/0000000000111 (B), that is, sum [7], an array element whose decimal number 7 is the ordinal number, sum [7] indicates that the first three groups of scores are used to obtain the first three scoring methods.. Similarly, when the status is //// 1111111111111 (B) ////, the maximum value is obtained. In the process of maximizing the value, an array is required to save the scoring method adopted by the maximum value of each policy status, in this way, the scoring method adopted by each policy status can be obtained based on the array. The reward score is calculated because the first six scores are greater than or/= 63 points plus 35 points, the total score of the first six scores of the same strategy needs to be distinguished, because the effect of the first six scores of a large value/equal to 63 is equivalent, so you only need to consider 0 ~ 63 in these 64 cases, a total score. If the total score of the first six items is greater than or equal to/63, the total score is placed in the total score element of the array number 63, if the value is less than 63, it is placed in the element with the corresponding score as the serial number. When comparing //, compare the total score of the first six elements with the same total score, and replace the original element with the total score, each item in the array stores the first six // item scores and the maximum total score equal to the serial number of the array element. For example, sum [1111011100011 (B)] [25] indicates the maximum total score of 25 for the first six scores in the Strategy // 1111011100011 (B, if the first six scores of this policy are 25, the // array element value is-1. The same scoring strategy used before and after replacement should be recorded during replacement and the first six scores should be recorded for backtracking of the obtained process. The time complexity of this algorithm is O (n * (2 ^ n), and the space complexity is O (2 ^ n ). # Include <iostream> # include <sstream> # include <algorithm> # include <cstring> using namespace std; # define NDICES5 // number of workers in each group. # Define NROUNDS13 // number of rounds for rolling. # Define NCOMBINATIONS8192 // 1 <13. The number of different combinations of scoring types. # Define NCATEGORIES13 // scoring type. # Define NUPPER64 // 63 (reward score condition) + 1 # define NBOUNS35 // reward score // The macro defined for calculating the number of digits of 1 in a binary number. # Define POW (c) (1 <(c) # define MASK (c) (unsigned long)-1)/(POW (c )) + 1) # define ROUND (n, c) (n) & MASK (c) + (n)> POW (c) & amp; MASK (c) // calculates the number of bits 1 when the integer n is a binary number. Int bits (int n) {n = ROUND (n, 0); n = ROUND (n, 1); n = ROUND (n, 2); n = ROUND (n, 3); n = ROUND (n, 4); return n ;}// calculate the score of a group of shards based on different scoring methods. For the last 6 scoring methods, you must first determine // whether the score meets the requirements of this scoring method. If yes, the corresponding score is returned. Otherwise, the score is 0. Int scoring (int dices [NDICES], int category) {// count one to six. Int ret = 0; if (category <6) {for (int I = 0; I <NDICES; I ++) if (dices [I] = (category + 1) ret + = dices [I];} else {switch (category) {// opportunity. Case 6: for (int I = 0; I <NDICES; I ++) ret + = dices [I]; break. Case 7: if (dices [0] = dices [2] | dices [1] = dices [3] | dices [2] = dices [4]) for (int I = 0; I <NDICES; I ++) ret + = dices [I]; break. Case 8: if (dices [0] = dices [3] | dices [1] = dices [4]) for (int I = 0; I <NDICES; I ++) ret + = dices [I]; break; // same as five. Case 9: if (dices [0] = dices [4]) ret = 50; break; // xiaoshun. Case 10: bool value [6]; memset (value, 0, sizeof (value); for (int I = 0; I <5; I ++) value [dices [I]-1] = true; for (int I = 0; I <3; I ++) if (value [I] & value [I + 1] & value [I + 2] & value [I + 3]) ret = 25; break; // Da Shun. Case 11: if (dices [1] = (dices [0] + 1) & dices [2] = (dices [1] + 1) & dices [3] = (dices [2] + 1) & dices [4] = (dices [3] + 1) ret = 35; break; // gourd. Case 12: if (dices [0] = dices [1] & dices [2] = dices [4] | dices [0] = dices [2] & dices [3] = dices [4]) ret = 40; break;} return ret;} void dynamic_programming (int yahtzee [NROUNDS] [NDICES]) {int score [NROUNDS] [NROUNDS]; // Save the scores of each group based on different scoring methods. Int sum [NCOMBINATIONS] [NUPPER]; // Save the total score of each policy. // Memo [NCOMBINATIONS] [NUPPER] [0] records the // scoring method used by each policy. memo [NCOMBINATIONS] [NUPPER] [1] records the first six scores. Int memo [NCOMBINATIONS] [NUPPER] [2]; // calculate the score of the Nth (I + 1) group when the Nth (j + 1) scoring method is used. For (int I = 0; I <NROUNDS; I ++) for (int j = 0; j <NCATEGORIES; j ++) score [I] [j] = scoring (yahtzee [I], j); // The initialization total score array is-1, and the total score is 0 if no policy is selected. Memset (sum,-1, sizeof (sum); sum [0] [0] = 0; int B, s, t, d,; // traverse all possible scoring combinations and calculate the maximum score of each combination. for (int m = 0; m <NCOMBINATIONS; m ++) for (int c = 0; c <NCATEGORIES; c ++) // you must ensure that the scoring method (c + 1) is not used. If (! (M & (1 <c) {// calculate the number of bits 1 when m is expressed as a binary number, indicating // The current value is (B + 1) select the scoring method for the group sequence. B = bits (m); // score of the (c + 1) scoring method in the (B + 1) group. S = score [B] [c]; // binary flag of the current policy. T = m | (1 <c); // If the selected scoring method is one of the first six ways, add the score in this group. A = (c <6 )? S: 0; for (int u = 0; u <NUPPER; u ++) if (sum [m] [u]>-1) {d = (u + a) <(NUPPER-1 )? (U + a): (NUPPER-1); if (sum [t] [d] <(sum [m] [u] + s )) {memo [t] [d] [0] = c; memo [t] [d] [1] = u; sum [t] [d] = sum [m] [u] + s ;}}// determine whether the maximum total score contains the reward score. Int max = 0, bouns = 0, upper, total; // The maximum total score for no reward points. For (int u = 0; u <NUPPER-1; u ++) if (sum [NCOMBINATIONS-1] [u]> max) {max = sum [NCOMBINATIONS-1] [u]; upper = u ;}// the maximum total score of the reward score. Total = max; if (sum [NCOMBINATIONS-1] [NUPPER-1]>-1) {bouns = NBOUNS; total = sum [NCOMBINATIONS-1] [NUPPER-1] + bouns;} // compare the total values of the two types. If (max <total) {max = total; upper = NUPPER-1 ;}// obtain the solution process based on the memo array backtracking. Int last = NCOMBINATIONS-1; int category [NROUNDS]; for (int I = NROUNDS-1; I> = 0; I --) {category [I] = memo [last] [upper] [0]; upper = memo [last] [upper] [1]; last ^ = (1 <category [I]);} // outputs the result based on the solution. For (int I = 0; I <NCATEGORIES; I ++) for (int j = 0; j <NROUNDS; j ++) if (category [j] = I) cout <score [j] [I] <"; cout <bouns <" <max <endl;} bool cmp (int a, int B) {return a <B;} int main (int ac, char * av []) {int yahtzee [NROUNDS] [NDICES]; string line; int count = 0; while (getline (cin, line) {istringstream iss (line); for (int I = 0; I <NDICES; I ++) iss> yahtzee [count % NROUNDS] [I]; sort (yahtzee [count % NROUNDS], yahtzee [count % NROUNDS] + NDICES, cmp ); if (++ count % NROUNDS = 0) dynamic_programming (yahtzee);} return 0 ;}