//------------------------------------------------------------------- // engima1351.c (c) 2005 by Charles Petzold (www.charlespetzold.com) // // "Let's Face It" from New Scientist, 30 July 2005, page 46. // // A cube is colored two faces red, two white, two blue. // It's cut up into smaller cubes of the same size. // A = number of smaller cubes with at least one red and one white face. // B = number of smaller cubes with at least one red and one blue face, but no white. // C = number of smaller cubes with at least one white face, but no red and no blue. // A and B are unequal but have reversed digits. // // The answer to the problem is C. // // There are 5 ways the cube can be colored: // Opposite faces are colored the same. // White faces only are opposite. // Red faces only are opposite. // Blue faces only are opposite. // No similarly colored faces are opposite. // In the comments below, I refer to these 5 possibilities as 'configurations.' // // The faces of the cube are numbered like so: // // +---+ // | 0 | // +---+---+ // | 2 | 1 | // +---+---+---+ // | 3 | 4 | // +---+---+ // | 5 | // +---+ // // There's really no particular advantage to this numbering scheme except // that opposite faces always differ by 3. (That is, opposite faces are // 0 and 3, 1 and 4, 2 and 5. #include #include // Define a couple macros to figure out when A and B have reversed digits. #define NUMDIGITS(N) ((N) <= 0 ? 0 : 1 + (int) log10(N)) #define DIGIT(N,I) (((N) / (int) pow(10, (I))) % 10) // Let's also define a simple enumeration so the code doesn't get // overly numeric. enum Color { White, Red, Blue }; int main(void) { // In the following array, the first dimension is the configuration // (defined above). The second dimension is a face of the cube, // numbered as shown above. int cubes[5][6] = { White, Red, Blue, White, Red, Blue, White, Red, Red, White, Blue, Blue, Red, Blue, Blue, Red, White, White, Blue, Red, Red, Blue, White, White, White, White, Red, Red, Blue, Blue }; // In the following array, the first dimension is the number of edges // of the cube. The second dimension indicates the two faces that meet // at that edge. The value of the array is the face number. int edges[12][2] = { 0,1, 0,2, 0,4, 0,5, 3,1, 3,2, 3,4, 3,5, 1,2, 2,5, 5,4, 4,1 }; // In the following arrray, the first dimension is the number of corners // of the cube. The second dimension indicates the three faces that meet // at that corner. The value of the array is the face number. int corners[8][3] = { 0,1,2, 0,2,5, 0,5,4, 0,4,1, 3,1,2, 3,2,5, 3,5,4, 3,4,1 }; // Define a bunch of other variables. int A, B, C; int divisions, cube, edge, corner, numdigits, i, clr, Is[3]; // The 'divisions' variable indicates how the cube is cut into // smaller cubes. A 'divisons' values of 1 means it's cut once // through each dimension, resulting in 8 smaller cubes. // A 'division' of 2 results in 27 smaller cubes, etc. for (divisions = 1; ; divisions++) { // Loop through the five configurations. for (cube = 0; cube < 5; cube++) { // Initialize the counts to zero. A = B = C = 0; // Loop through the 12 edges of the cube. for (edge = 0; edge < 12; edge++) { // The array named 'Is' indicates if a particular color is // present on that edge. For example, Is[Blue] is 1 // if blue is on the edge and 0 otherwise. // So, loop through the three colors. Index 'cubes' // by 'cube' (the configuration) and 'edges', which // indicates the faces that constitute the edge. for (clr = 0; clr < 3; clr++) Is[clr] = cubes[cube][edges[edge][0]] == clr || cubes[cube][edges[edge][1]] == clr; // For each edge that meets the criteria, increment // A, B, and C by the number of non-corner smaller cubes // on that edge. if (Is[Red] && Is[White]) A += divisions - 1; if (Is[Red] && Is[Blue] && !Is[White]) B += divisions - 1; if (Is[White] && !Is[Red] && !Is[Blue]) C += divisions - 1; } // Loop through the 8 corners of the cube. for (corner = 0; corner < 8; corner++) { // Similarly, set Is[White], Is[Red], and Is[Blue] to indicate // if that color is on the corner. for (clr = 0; clr < 3; clr++) Is[clr] = cubes[cube][corners[corner][0]] == clr || cubes[cube][corners[corner][1]] == clr || cubes[cube][corners[corner][2]] == clr; // Increment A, B, and C for each corner satisfying the criteria. if (Is[Red] && Is[White]) A++; if (Is[Red] && Is[Blue] && !Is[White]) B++; if (Is[White] && !Is[Red] && !Is[Blue]) C++; } // Don't forget to add to C the internal squares on two white faces. C += 2 * (divisions - 1) * (divisions - 1); // A and B must be unequal but have the same number of digits, // and these digits must be reversed. numdigits = NUMDIGITS(A); if (numdigits < 2 || A == B || numdigits != NUMDIGITS(B)) continue; for (i = 0; i < numdigits; i++) if (DIGIT(A,i) != DIGIT(B, numdigits - i - 1)) break; if (i != numdigits) continue; // If we've gotten this far, it's an answer. printf("divisions = %i cube = %i A = %i B = %i C = %i\n", divisions, cube, A, B, C); return 1; // The answer results when divisions is 11 and the cube configuration is 3 // (that is, blue faces only are opposite). // However, if you remove the return statement after printf, you'll find // that divisions of 101, 1001, and 100001, also work. } } return 1; }