263 lines
7.3 KiB
C
263 lines
7.3 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <omp.h>
|
|
|
|
#define CHARS_MAX 4*1024
|
|
#define MAX_PATTERNS 1024
|
|
#define MAX_PATTERN_ELEMENTS 1024
|
|
#define MAX_DESIGNS 1024
|
|
#define MAX_DESIGN_ELEMENTS 1024
|
|
#define COLOR_COUNT 5
|
|
|
|
#define cti(a) ((a) == 'w' ? 0 : (((a) == 'u' ? 1 : ((a) == 'b' ? 2 : ((a) == 'r' ? 3 : 4)))))
|
|
|
|
typedef struct sequence {
|
|
char *colors;
|
|
int count;
|
|
} sequence_t;
|
|
|
|
typedef struct node {
|
|
struct node *children[COLOR_COUNT];
|
|
uint64_t variants;
|
|
char key;
|
|
uint8_t is_leaf;
|
|
} node_t;
|
|
|
|
node_t* create_node() {
|
|
node_t *node = calloc(1, sizeof(node[0]));
|
|
return node;
|
|
}
|
|
|
|
node_t* search(node_t* root, char* word, int len) {
|
|
node_t* node = root;
|
|
for (int i = 0; i < len; i++) {
|
|
if (node->children[cti(word[i])] == NULL) {
|
|
return NULL;
|
|
}
|
|
node = node->children[cti(word[i])];
|
|
}
|
|
return node;
|
|
}
|
|
|
|
void insert(node_t* root, char* word, int len, uint64_t variants) {
|
|
node_t* node = root;
|
|
for (int i = 0; i < len; i++) {
|
|
if (node->children[cti(word[i])] == NULL) {
|
|
node->children[cti(word[i])] = create_node();
|
|
}
|
|
node = node->children[cti(word[i])];
|
|
}
|
|
node->variants = variants;
|
|
node->is_leaf = 1;
|
|
}
|
|
|
|
void free_node(node_t* node) {
|
|
for (int i = 0; i < COLOR_COUNT; i++) {
|
|
if (node->children[i] != NULL) {
|
|
free_node(node->children[i]);
|
|
}
|
|
}
|
|
|
|
free(node);
|
|
}
|
|
|
|
int possible(sequence_t design, node_t *pattern_trie);
|
|
uint64_t possible_variants(sequence_t design, node_t* pattern_trie, node_t* variant_trie);
|
|
|
|
int main() {
|
|
char *p, *buf, c;
|
|
|
|
buf = calloc(CHARS_MAX, sizeof(char));
|
|
p = buf;
|
|
|
|
sequence_t *designs = calloc(MAX_DESIGNS, sizeof(designs[0]));
|
|
for (int i = 0; i < MAX_DESIGNS; i++) {
|
|
designs[i].colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(designs[0].colors[0]));
|
|
}
|
|
int design_count = 0;
|
|
|
|
sequence_t *patterns = calloc(MAX_PATTERNS, sizeof(patterns[0]));
|
|
for (int i = 0; i < MAX_PATTERNS; i++) {
|
|
patterns[i].colors = calloc(MAX_PATTERN_ELEMENTS, sizeof(patterns[0].colors[0]));
|
|
}
|
|
int pattern_count = 0;
|
|
|
|
int reading_available_patterns = 1;
|
|
|
|
while ((c = getchar()) != EOF) {
|
|
if (reading_available_patterns) {
|
|
*p++ = c;
|
|
if (c != '\n') {
|
|
continue;
|
|
}
|
|
if (buf[0] == '\n') {
|
|
reading_available_patterns = 0;
|
|
continue;
|
|
}
|
|
|
|
char *q = p;
|
|
p = buf;
|
|
|
|
do {
|
|
while (*p != '\n' && *p != ',') {
|
|
patterns[pattern_count].colors[patterns[pattern_count].count++] = *p;
|
|
p++;
|
|
}
|
|
pattern_count++;
|
|
p += 2;
|
|
} while (p < q);
|
|
|
|
memset(buf, 0, CHARS_MAX);
|
|
p = buf;
|
|
} else {
|
|
if (c == '\n') {
|
|
design_count++;
|
|
continue;
|
|
}
|
|
designs[design_count].colors[designs[design_count].count++] = c;
|
|
}
|
|
}
|
|
|
|
uint32_t shortest_pattern = UINT32_MAX, longest_pattern = 0;
|
|
for (int i = 0; i < pattern_count; i++) {
|
|
if (patterns[i].count < shortest_pattern) {
|
|
shortest_pattern = patterns[i].count;
|
|
}
|
|
if (patterns[i].count > longest_pattern) {
|
|
longest_pattern = patterns[i].count;
|
|
}
|
|
}
|
|
|
|
node_t *pattern_trie = calloc(1, sizeof(pattern_trie[0]));
|
|
|
|
for (int i = 0; i < pattern_count; i++) {
|
|
sequence_t current_sequence = { 0 };
|
|
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
|
|
insert(pattern_trie, patterns[i].colors, patterns[i].count, 0);
|
|
free(current_sequence.colors);
|
|
}
|
|
|
|
int part1 = 0;
|
|
uint64_t part2 = 0;
|
|
// Try to build each design out of the available patterns
|
|
#pragma omp parallel for
|
|
for (int i = 0; i < design_count; i++) {
|
|
sequence_t current_sequence = { 0 };
|
|
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
|
|
|
|
if (possible(designs[i], pattern_trie))
|
|
#pragma omp critical
|
|
{
|
|
part1++;
|
|
}
|
|
|
|
free(current_sequence.colors);
|
|
}
|
|
|
|
node_t *variant_trie = calloc(1, sizeof(variant_trie[0]));
|
|
|
|
for (int i = 0; i < design_count; i++) {
|
|
sequence_t current_sequence = { 0 };
|
|
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
|
|
|
|
part2 += possible_variants(designs[i], pattern_trie, variant_trie);
|
|
|
|
free(current_sequence.colors);
|
|
}
|
|
|
|
free(buf);
|
|
for (int i = 0; i < MAX_DESIGNS; i++) {
|
|
free(designs[i].colors);
|
|
}
|
|
free(designs);
|
|
for (int i = 0; i < MAX_PATTERNS; i++) {
|
|
free(patterns[i].colors);
|
|
}
|
|
free(patterns);
|
|
free_node(pattern_trie);
|
|
free_node(variant_trie);
|
|
|
|
printf("%i\n", part1);
|
|
printf("%lu\n", part2);
|
|
}
|
|
|
|
int possible(sequence_t design, node_t *pattern_trie) {
|
|
node_t *node = search(pattern_trie, design.colors, design.count);
|
|
|
|
if (node != NULL) {
|
|
return 1;
|
|
}
|
|
|
|
for (int i = 1; i <= design.count; i++) {
|
|
char *pattern = calloc(i, sizeof(pattern[0]));
|
|
memcpy(pattern, design.colors, i*sizeof(pattern[0]));
|
|
node_t *node = search(pattern_trie, pattern, i);
|
|
|
|
free(pattern);
|
|
|
|
if (node == NULL || node->is_leaf == 0) {
|
|
continue;
|
|
}
|
|
|
|
sequence_t subdesign = { 0 };
|
|
subdesign.count = design.count - i;
|
|
subdesign.colors = calloc(subdesign.count, sizeof(subdesign.colors[0]));
|
|
memcpy(subdesign.colors, design.colors + i, subdesign.count*sizeof(subdesign.colors[0]));
|
|
|
|
int good = possible(subdesign, pattern_trie);
|
|
free(subdesign.colors);
|
|
if (good) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint64_t possible_variants(sequence_t design, node_t* pattern_trie, node_t* variant_trie) {
|
|
if (design.count == 0) {
|
|
return 1;
|
|
}
|
|
char *pattern = calloc(design.count+1, sizeof(pattern[0]));
|
|
memcpy(pattern, design.colors, (design.count+1)*sizeof(pattern[0]));
|
|
pattern[design.count] = '\0';
|
|
|
|
node_t *node = search(variant_trie, design.colors, design.count);
|
|
|
|
// We already know the answer
|
|
if (node != NULL && node->is_leaf) {
|
|
char *pattern = calloc(design.count+1, sizeof(pattern[0]));
|
|
memcpy(pattern, design.colors, (design.count+1)*sizeof(pattern[0]));
|
|
pattern[design.count] = '\0';
|
|
return node->variants;
|
|
}
|
|
|
|
uint64_t count = 0;
|
|
// Try all possible patterns
|
|
for (int i = 1; i <= design.count; i++) {
|
|
char *pattern = calloc(i+1, sizeof(pattern[0]));
|
|
memcpy(pattern, design.colors, (i+1)*sizeof(pattern[0]));
|
|
node_t *node = search(pattern_trie, pattern, i);
|
|
pattern[i] = '\0';
|
|
|
|
if (node == NULL || node->is_leaf == 0) {
|
|
continue;
|
|
}
|
|
free(pattern);
|
|
|
|
sequence_t subdesign = { 0 };
|
|
subdesign.count = design.count - i;
|
|
subdesign.colors = calloc(subdesign.count, sizeof(subdesign.colors[0]));
|
|
memcpy(subdesign.colors, design.colors + i, subdesign.count*sizeof(subdesign.colors[0]));
|
|
|
|
count += possible_variants(subdesign, pattern_trie, variant_trie);
|
|
free(subdesign.colors);
|
|
}
|
|
|
|
insert(variant_trie, design.colors, design.count, count);
|
|
|
|
return count;
|
|
}
|