A binary 8x8 matrix is 'unholy' if there are no isolated 1s. A 1 is isolated if there isn't another 1 in any of the 4 direct cardinal directions. Write a C program that counts the total number of unholy 8x8 matricies.
A binary 8x8 matrix is 'unholy' if there are no isolated 1s. A 1 is isolated if there isn't another 1 in any of the 4 direct cardinal directions. Write a C program that counts the total number of unholy 8x8 matricies.
To solve this problem, we need to count the number of 8x8 binary matrices where no 1 is isolated. A 1 is considered isolated if it does not have another 1 in any of the four direct cardinal directions (up, down, left, right). Given the size of the matrix, a brute-force approach is infeasible, so we use dynamic programming (DP) with precomputed validity checks to efficiently count valid matrices. ### Approach 1. **Precomputation**: - **Validity Check**: For each possible pair of rows (current and next), determine if all 1s in the next row have horizontal or vertical neighbors. - **Required Next Row**: For each row, compute the positions that must be set to 1 in the next row to avoid isolated 1s. 2. **Dynamic Programming**: - **Initialization**: Start with all possible configurations for the first row. - **Transition**: For each row, transition to the next row's configurations that are valid and meet the required positions. - **Final Count**: Sum up all valid configurations for the last row. ### Solution Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include <stdio.h> #include <stdint.h> #define ROWS 8 #define COLS 8 uint8_t valid[256][256]; uint8_t required_next_table[256]; void precompute() { // Precompute valid transitions between current and next row for (int current = 0; current < 256; current++) { for (int next = 0; next < 256; next++) { valid[current][next] = 1; for (int j = 0; j < COLS; j++) { if ((next >> j) & 1) { int has_horizontal = 0; if (j > 0 && ((next >> (j - 1)) & 1)) has_horizontal = 1; if (j < COLS - 1 && ((next >> (j + 1)) & 1)) has_horizontal = 1; int has_vertical = (current >> j) & 1; if (!has_horizontal && !has_vertical) { valid[current][next] = 0; break; } } } } } // Precompute required_next for each current row for (int current = 0; current < 256; current++) { uint8_t required = 0; for (int j = 0; j < COLS; j++) { if ((current >> j) & 1) { int left = (j > 0) ? ((current >> (j - 1)) & 1) : 0; int right = (j < COLS - 1) ? ((current >> (j + 1)) & 1) : 0; if (!left && !right) { required |= (1 << j); } } } required_next_table[current] = required; } } int main() { precompute(); uint64_t dp[ROWS][256] = {0}; // Initialize row 0 for (int current = 0; current < 256; current++) { dp[0][current] = 1; } // Process row 0 to row 1 for (int current = 0; current < 256; current++) { uint8_t required = required_next_table[current]; for (int next = 0; next < 256; next++) { if ((next & required) == required && valid[current][next]) { dp[1][next] += dp[0][current]; } } } // Process rows 1 to 6 for (int row = 1; row < ROWS - 1; row++) { for (int current = 0; current < 256; current++) { if (dp[row][current] == 0) continue; for (int next = 0; next < 256; next++) { if (valid[current][next]) { dp[row + 1][next] += dp[row][current]; } } } } // Sum all valid configurations for the last row (row 7) uint64_t total = 0; for (int current = 0; current < 256; current++) { total += dp[ROWS - 1][current]; } printf("%llu\n", total); return 0; } |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include <stdio.h> #include <stdint.h> #define ROWS 8 #define COLS 8 uint8_t valid[256][256]; uint8_t required_next_table[256]; void precompute() { // Precompute valid transitions between current and next row for (int current = 0; current < 256; current++) { for (int next = 0; next < 256; next++) { valid[current][next] = 1; for (int j = 0; j < COLS; j++) { if ((next >> j) & 1) { int has_horizontal = 0; if (j > 0 && ((next >> (j - 1)) & 1)) has_horizontal = 1; if (j < COLS - 1 && ((next >> (j + 1)) & 1)) has_horizontal = 1; int has_vertical = (current >> j) & 1; if (!has_horizontal && !has_vertical) { valid[current][next] = 0; break; } } } } } // Precompute required_next for each current row for (int current = 0; current < 256; current++) { uint8_t required = 0; for (int j = 0; j < COLS; j++) { if ((current >> j) & 1) { int left = (j > 0) ? ((current >> (j - 1)) & 1) : 0; int right = (j < COLS - 1) ? ((current >> (j + 1)) & 1) : 0; if (!left && !right) { required |= (1 << j); } } } required_next_table[current] = required; } } int main() { precompute(); uint64_t dp[ROWS][256] = {0}; // Initialize row 0 for (int current = 0; current < 256; current++) { dp[0][current] = 1; } // Process row 0 to row 1 for (int current = 0; current < 256; current++) { uint8_t required = required_next_table[current]; for (int next = 0; next < 256; next++) { if ((next & required) == required && valid[current][next]) { dp[1][next] += dp[0][current]; } } } // Process rows 1 to 6 for (int row = 1; row < ROWS - 1; row++) { for (int current = 0; current < 256; current++) { if (dp[row][current] == 0) continue; for (int next = 0; next < 256; next++) { if (valid[current][next]) { dp[row + 1][next] += dp[row][current]; } } } } // Sum all valid configurations for the last row (row 7) uint64_t total = 0; for (int current = 0; current < 256; current++) { total += dp[ROWS - 1][current]; } printf("%llu\n", total); return 0; } |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include <stdio.h> #include <stdint.h> #define ROWS 8 #define COLS 8 uint8_t valid[256][256]; uint8_t required_next_table[256]; void precompute() { // Precompute valid transitions between current and next row for (int current = 0; current < 256; current++) { for (int next = 0; next < 256; next++) { valid[current][next] = 1; for (int j = 0; j < COLS; j++) { if ((next >> j) & 1) { int has_horizontal = 0; if (j > 0 && ((next >> (j - 1)) & 1)) has_horizontal = 1; if (j < COLS - 1 && ((next >> (j + 1)) & 1)) has_horizontal = 1; int has_vertical = (current >> j) & 1; if (!has_horizontal && !has_vertical) { valid[current][next] = 0; break; } } } } } // Precompute required_next for each current row for (int current = 0; current < 256; current++) { uint8_t required = 0; for (int j = 0; j < COLS; j++) { if ((current >> j) & 1) { int left = (j > 0) ? ((current >> (j - 1)) & 1) : 0; int right = (j < COLS - 1) ? ((current >> (j + 1)) & 1) : 0; if (!left && !right) { required |= (1 << j); } } } required_next_table[current] = required; } } int main() { precompute(); uint64_t dp[ROWS][256] = {0}; // Initialize row 0 for (int current = 0; current < 256; current++) { dp[0][current] = 1; } // Process row 0 to row 1 for (int current = 0; current < 256; current++) { uint8_t required = required_next_table[current]; for (int next = 0; next < 256; next++) { if ((next & required) == required && valid[current][next]) { dp[1][next] += dp[0][current]; } } } // Process rows 1 to 6 for (int row = 1; row < ROWS - 1; row++) { for (int current = 0; current < 256; current++) { if (dp[row][current] == 0) continue; for (int next = 0; next < 256; next++) { if (valid[current][next]) { dp[row + 1][next] += dp[row][current]; } } } } // Sum all valid configurations for the last row (row 7) uint64_t total = 0; for (int current = 0; current < 256; current++) { total += dp[ROWS - 1][current]; } printf("%llu\n", total); return 0; } |
132797167652221230
main.c: In function 'main':
main.c:85:16: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'uint64_t' {aka 'long unsigned int'} [-Wformat=]
85 | printf("%llu\n", total);
| ~~~^ ~~~~~
| | |
| | uint64_t {aka long unsigned int}
| long long unsigned int
| %lu
Testing if the previous output contains the string 1121231537486377866
: False