//-------------------------------------------------------------------
// 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;
}