day08.c (4980B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <inttypes.h> 4 #include <math.h> 5 #include <stdbool.h> 6 #include <string.h> 7 #include <strings.h> 8 #include "cputime.h" 9 10 typedef union { 11 struct { int x, y, z; }; 12 int n[3]; 13 } Point; 14 15 typedef struct { 16 Point *p1; 17 Point *p2; 18 int d; 19 } Distance; 20 21 typedef struct { 22 int id; 23 Point *points[1000]; 24 int points_l; 25 } Circuit; 26 27 static int btoi(int bufl, int buf[bufl]) { 28 int num = 0; 29 for (int i=0;i<bufl;++i) num = num*10+buf[i]; 30 return num; 31 } 32 33 static int dist(Point p1, Point p2) { 34 return sqrt(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2)+pow(p1.z-p2.z,2)); 35 } 36 37 static int cmp_dist(const void *vd1, const void *vd2) { 38 Distance *d1 = (Distance *)vd1; 39 Distance *d2 = (Distance *)vd2; 40 return d1->d - d2->d; 41 } 42 43 static bool has_point(Circuit *cir, const Point *p) { 44 for (int i=0;i<cir->points_l;++i) { 45 if (cir->points[i]==p) return true; 46 } 47 return false; 48 } 49 50 static void circuits_add(int *cirs_l, Circuit *cirs, Distance *dist) { 51 for (int i=0;i<*cirs_l;++i) { 52 Circuit *cir = &cirs[i]; 53 bool hit1 = has_point(cir, dist->p1); 54 bool hit2 = has_point(cir, dist->p2); 55 if (hit1&&hit2) { // both points are already in circuit 56 return; 57 } else if (hit1||hit2) { // only one of two points found 58 cir->points[cir->points_l++] = hit1?dist->p2:dist->p1; 59 return; 60 } 61 } 62 63 int cir_id = (*cirs_l)++; 64 Circuit *cir = &cirs[cir_id]; 65 cir->id = cir_id; 66 cir->points[cir->points_l++] = dist->p1; 67 cir->points[cir->points_l++] = dist->p2; 68 } 69 70 static bool circuits_overlap(Circuit *cir1, Circuit *cir2) { 71 for (int i=0;i<cir1->points_l;++i) { 72 if (has_point(cir2, cir1->points[i])) { 73 return true; 74 } 75 } 76 return false; 77 } 78 79 static void circuit_merge(Circuit *to, Circuit *from) { 80 for (int i=0;i<from->points_l;++i) { 81 if (!has_point(to, from->points[i])) { 82 to->points[to->points_l++] = from->points[i]; 83 } 84 } 85 from->points_l = 0; 86 } 87 88 static int cmp_circuits(const void *vc1, const void *vc2) { 89 const Circuit *c1 = (const Circuit *)vc1; 90 const Circuit *c2 = (const Circuit *)vc2; 91 return c2->points_l - c1->points_l; 92 } 93 94 static int circuits_merge(int circuits_l, Circuit *circuits) { 95 int new_len = circuits_l; 96 for (int i=0;i<circuits_l;++i) { 97 for (int j=i;j<circuits_l;++j) { 98 Circuit *cir1 = &circuits[i]; 99 Circuit *cir2 = &circuits[j]; 100 if (i==j) continue; 101 if (cir1==cir2) continue; 102 if (circuits_overlap(cir1, cir2)) { 103 circuit_merge(cir1, cir2); 104 new_len--; 105 break; 106 } 107 } 108 } 109 qsort(circuits, circuits_l, sizeof(Circuit), cmp_circuits); 110 return new_len; 111 } 112 113 #define MAX_POINTS 1000 114 115 int main(void) { 116 uint64_t part1 = 0; 117 uint64_t part2 = 0; 118 Point *points = calloc(MAX_POINTS, sizeof(Point)); 119 int points_l = 0; 120 int *n = points[0].n; 121 int buf[16] = {0}; 122 int bufl = 0; 123 for (int c=getchar();c!=EOF;c=getchar()) { 124 if (c>='0'&&c<='9') buf[bufl++] = c-'0'; 125 else if (c==','||c=='\n') { 126 *n = btoi(bufl, buf); 127 bufl = 0; 128 n++; 129 if (c=='\n') n = points[++points_l].n; 130 } 131 if (points_l>MAX_POINTS) { 132 printf("Too many input points, max: %d\n", MAX_POINTS); 133 return 1; 134 } 135 } 136 const int dists_cnt = (points_l*points_l-points_l)/2; 137 const int conns_cnt = dists_cnt<1000 ? 10 : 1000; 138 Distance *dists = calloc(dists_cnt, sizeof(Distance)); 139 int dists_l = 0; 140 for (int i1=0;i1<points_l;++i1) { 141 for (int i2=i1;i2<points_l;++i2) { 142 if (i1==i2) continue; 143 Point *p1 = &points[i1]; 144 Point *p2 = &points[i2]; 145 int d = dist(points[i1], points[i2]); 146 dists[dists_l++] = (Distance){ p1, p2, d }; 147 } 148 } 149 qsort(dists, dists_l, sizeof(Distance), cmp_dist); 150 Circuit *circuits = calloc(conns_cnt*2, sizeof(Circuit)); 151 int circuits_l = 0; 152 for (int i=0;i<conns_cnt;++i) { 153 circuits_add(&circuits_l, circuits, &dists[i]); 154 circuits_l = circuits_merge(circuits_l, circuits); 155 } 156 qsort(circuits, circuits_l, sizeof(Circuit), cmp_circuits); 157 part1 = circuits[0].points_l*circuits[1].points_l*circuits[2].points_l; 158 free(circuits); 159 // ---------------- p2 ------------------- 160 circuits = calloc(dists_l/2, sizeof(Circuit)); 161 circuits_l = 0; 162 for (int i=0;i<dists_l;++i) { 163 circuits_add(&circuits_l, circuits, &dists[i]); 164 circuits_l = circuits_merge(circuits_l, circuits); 165 if (circuits[0].points_l==points_l) { 166 part2 = dists[i].p1->x * dists[i].p2->x; 167 break; 168 } 169 } 170 free(circuits); 171 free(dists); 172 free(points); 173 174 printf("p1: %"PRIu64"\np2: %"PRIu64"\n", part1, part2); 175 return 0; 176 }