#include #include #include #include #include #define LINE_MAX_LENGTH 256 #define MAX_ENTRIES 2048 #define MAX_QUEUE_LEN 256 #define MAX_EDGES 1024 #define MAX_BREAKPOINTS 512 #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) typedef struct entry { char direction; long long count; char rgb_string[10]; } entry_t; typedef struct zone { long long upper_left_corner[2]; long long lower_right_corner[2]; uint8_t outside; } zone_t; int cmp(const void* a, const void* b); int on_edge(long long edges[MAX_EDGES][2][2], int edges_num, long long side[2][2]); unsigned long long lake_volume(entry_t entries[], int entries_num); void decode_rgbs(entry_t entries[], int entries_num); int main() { char *p, *buf, c; buf = (char *)malloc(LINE_MAX_LENGTH); memset(buf, 0, LINE_MAX_LENGTH); p = buf; entry_t entries[MAX_ENTRIES]; memset(entries, 0, MAX_ENTRIES * sizeof(entry_t)); int entries_num = 0; while ((c = getchar()) != EOF) { *p++ = c; if (c == '\n') { sscanf(buf, "%c %lli %s", &entries[entries_num].direction, &entries[entries_num].count, entries[entries_num].rgb_string); entries_num++; memset(buf, 0, LINE_MAX_LENGTH); p = buf; } } unsigned long long part1 = lake_volume(entries, entries_num); decode_rgbs(entries, entries_num); unsigned long long part2 = lake_volume(entries, entries_num); printf("%llu\n", part1); printf("%llu\n", part2); free(buf); } int cmp(const void* a, const void* b) { return *(long long*)a - *(long long*)b; } int on_edge(long long edges[MAX_EDGES][2][2], int edges_num, long long side[2][2]) { for (int i = 0; i < edges_num; i++) { if (edges[i][0][0] == side[0][0] && edges[i][0][0] == edges[i][1][0] && side[0][0] == side[1][0] && edges[i][0][1] <= side[0][1] && edges[i][1][1] >= side[1][1]) { return 1; } if (edges[i][0][1] == side[0][1] && edges[i][0][1] == edges[i][1][1] && side[0][1] == side[1][1] && edges[i][0][0] <= side[0][0] && edges[i][1][0] >= side[1][0]) { return 1; } } return 0; } unsigned long long lake_volume(entry_t entries[], int entries_num) { long long x = 0, y = 0, dir[2]; long long edges[MAX_EDGES][2][2]; memset(edges, 0, MAX_EDGES * 2 * 2 * sizeof(long long)); int edges_num = 0; for (int i = 0; i < entries_num; i++) { switch (entries[i].direction) { case 'R': dir[0] = 1; dir[1] = 0; edges[edges_num][0][0] = x; edges[edges_num][0][1] = y; edges[edges_num][1][0] = x + entries[i].count * dir[0]; edges[edges_num][1][1] = y + entries[i].count * dir[1]; edges_num++; break; case 'L': dir[0] = -1; dir[1] = 0; edges[edges_num][1][0] = x; edges[edges_num][1][1] = y; edges[edges_num][0][0] = x + entries[i].count * dir[0]; edges[edges_num][0][1] = y + entries[i].count * dir[1]; edges_num++; break; case 'U': dir[0] = 0; dir[1] = -1; edges[edges_num][1][0] = x; edges[edges_num][1][1] = y; edges[edges_num][0][0] = x + entries[i].count * dir[0]; edges[edges_num][0][1] = y + entries[i].count * dir[1]; edges_num++; break; case 'D': dir[0] = 0; dir[1] = 1; edges[edges_num][0][0] = x; edges[edges_num][0][1] = y; edges[edges_num][1][0] = x + entries[i].count * dir[0]; edges[edges_num][1][1] = y + entries[i].count * dir[1]; edges_num++; break; } x += entries[i].count * dir[0]; y += entries[i].count * dir[1]; } // Find smallest and largest x and y long long min_x = LLONG_MAX, max_x = LLONG_MIN, min_y = LLONG_MAX, max_y = LLONG_MIN; for (int i = 0; i < edges_num; i++) { if (edges[i][0][0] < min_x) { min_x = edges[i][0][0]; } if (edges[i][1][0] > max_x) { max_x = edges[i][1][0]; } if (edges[i][0][1] < min_y) { min_y = edges[i][0][1]; } if (edges[i][1][1] > max_y) { max_y = edges[i][1][1]; } } // X breakpoints long long x_breakpoints[MAX_BREAKPOINTS], x_breakpoints_num = 0; for (int i = 0; i < edges_num; i++) { int found = 0; for (int j = 0; j < x_breakpoints_num; j++) { if (edges[i][0][0] == x_breakpoints[j]) { found = 1; break; } } if (!found) { x_breakpoints[x_breakpoints_num] = edges[i][0][0]; x_breakpoints_num++; } found = 0; for (int j = 0; j < x_breakpoints_num; j++) { if (edges[i][1][0] == x_breakpoints[j]) { found = 1; break; } } if (!found) { x_breakpoints[x_breakpoints_num] = edges[i][1][0]; x_breakpoints_num++; } } qsort(x_breakpoints, x_breakpoints_num, sizeof(x_breakpoints[0]), &cmp); // Y breakpoints long long y_breakpoints[MAX_BREAKPOINTS], y_breakpoints_num = 0; for (int i = 0; i < edges_num; i++) { int found = 0; for (int j = 0; j < y_breakpoints_num; j++) { if (edges[i][0][1] == y_breakpoints[j]) { found = 1; break; } } if (!found) { y_breakpoints[y_breakpoints_num] = edges[i][0][1]; y_breakpoints_num++; } found = 0; for (int j = 0; j < y_breakpoints_num; j++) { if (edges[i][1][1] == y_breakpoints[j]) { found = 1; break; } } if (!found) { y_breakpoints[y_breakpoints_num] = edges[i][1][1]; y_breakpoints_num++; } } qsort(y_breakpoints, y_breakpoints_num, sizeof(y_breakpoints[0]), &cmp); zone_t **zones = (zone_t**)malloc((x_breakpoints_num - 1) * sizeof(zone_t*)); for (int i = 0; i < x_breakpoints_num - 1; i++) { zones[i] = (zone_t*)malloc((y_breakpoints_num - 1) * sizeof(zone_t)); memset(zones[i], 0, (y_breakpoints_num - 1) * sizeof(zone_t)); } zone_t *curr; for (int i = 0; i < y_breakpoints_num - 1; i++) { for (int j = 0; j < x_breakpoints_num - 1; j++) { curr = &zones[j][i]; curr->upper_left_corner[0] = x_breakpoints[j]; curr->upper_left_corner[1] = y_breakpoints[i]; curr->lower_right_corner[0] = x_breakpoints[j + 1]; curr->lower_right_corner[1] = y_breakpoints[i + 1]; } } // Mark zones as outside int found = 1; while (found) { found = 0; for (int i = 0; i < y_breakpoints_num - 1; i++) { for (int j = 0; j < x_breakpoints_num - 1; j++) { if (zones[j][i].outside) { continue; } // LEFT long long side[2][2]; side[0][0] = zones[j][i].upper_left_corner[0]; side[0][1] = zones[j][i].upper_left_corner[1]; side[1][0] = zones[j][i].upper_left_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (j == 0 && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } if (j > 0 && zones[j-1][i].outside && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } // RIGHT side[0][0] = zones[j][i].lower_right_corner[0]; side[0][1] = zones[j][i].upper_left_corner[1]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (j == x_breakpoints_num - 2 && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } if (j < x_breakpoints_num - 2 && zones[j+1][i].outside && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } // UP side[0][0] = zones[j][i].upper_left_corner[0]; side[0][1] = zones[j][i].upper_left_corner[1]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].upper_left_corner[1]; if (i == 0 && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } if (i > 0 && zones[j][i-1].outside && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } // DOWN side[0][0] = zones[j][i].upper_left_corner[0]; side[0][1] = zones[j][i].lower_right_corner[1]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (i == y_breakpoints_num - 2 && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } if (i < y_breakpoints_num - 2 && zones[j][i+1].outside && !on_edge(edges, edges_num, side)) { zones[j][i].outside = 1; found = 1; } } } } unsigned long long sum = 0; unsigned long long out = 0; for (int i = 0; i < y_breakpoints_num - 1; i++) { for (int j = 0; j < x_breakpoints_num - 1; j++) { if (zones[j][i].outside) { out++; } } } for (int i = 0; i < y_breakpoints_num - 1; i++) { for (int j = 0; j < x_breakpoints_num - 1; j++) { if (zones[j][i].outside) { continue; } sum += (zones[j][i].lower_right_corner[0] - zones[j][i].upper_left_corner[0] - 1) * (zones[j][i].lower_right_corner[1] - zones[j][i].upper_left_corner[1] - 1); // RIGHT long long side[2][2]; side[0][0] = zones[j][i].lower_right_corner[0]; side[0][1] = zones[j][i].upper_left_corner[1]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (!on_edge(edges, edges_num, side)) { sum += side[1][1] - side[0][1] - 1; } // DOWN side[0][1] = zones[j][i].lower_right_corner[1]; side[0][0] = zones[j][i].upper_left_corner[0]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (!on_edge(edges, edges_num, side)) { sum += side[1][0] - side[0][0] - 1; } // CORNER side[0][1] = zones[j][i].lower_right_corner[1]; side[0][0] = zones[j][i].lower_right_corner[0]; side[1][0] = zones[j][i].lower_right_corner[0]; side[1][1] = zones[j][i].lower_right_corner[1]; if (!on_edge(edges, edges_num, side)) { sum++; } } } for (int i = 0; i < edges_num; i++) { sum += (edges[i][1][0] - edges[i][0][0]) + (edges[i][1][1] - edges[i][0][1]); } for (int i = 0; i < x_breakpoints_num - 1; i++) { free(zones[i]); } free(zones); return sum; } void decode_rgbs(entry_t entries[], int entries_num) { for (int i = 0; i < entries_num; i++) { char value[6], *p; memset(value, 0, 6); p = entries[i].rgb_string; while(*p != '#') p++; p++; strncpy(value, p, 5); sscanf(value, "%llx", &entries[i].count); switch(entries[i].rgb_string[7]) { case '0': entries[i].direction = 'R'; break; case '1': entries[i].direction = 'D'; break; case '2': entries[i].direction = 'L'; break; case '3': entries[i].direction = 'U'; break; } } }