diff options
Diffstat (limited to '2023/24')
| -rw-r--r-- | 2023/24/24a.c | 76 | ||||
| -rw-r--r-- | 2023/24/24b.c | 205 |
2 files changed, 281 insertions, 0 deletions
diff --git a/2023/24/24a.c b/2023/24/24a.c new file mode 100644 index 0000000..6c75c08 --- /dev/null +++ b/2023/24/24a.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | #include <stdbool.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | |||
| 5 | #define N 300 | ||
| 6 | #define XMIN 2e14 | ||
| 7 | #define XMAX 4e14 | ||
| 8 | #define eps 1e-6 | ||
| 9 | |||
| 10 | #define ABS(x) ((x)>0?(x):-(x)) | ||
| 11 | |||
| 12 | typedef struct { double x, y, z; } point_t; | ||
| 13 | typedef struct { point_t p, v; } line_t; | ||
| 14 | |||
| 15 | char *buf, line[N]; | ||
| 16 | int n, s; | ||
| 17 | line_t l[N]; | ||
| 18 | |||
| 19 | bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; } | ||
| 20 | |||
| 21 | line_t readl(char *buf) { | ||
| 22 | double a[6]; | ||
| 23 | for (int i = 0; i < 6; i++) { | ||
| 24 | a[i] = (double)atoll(buf); | ||
| 25 | while (isnum(*buf)) buf++; | ||
| 26 | while (*buf != '\n' && !isnum(*buf)) buf++; | ||
| 27 | } | ||
| 28 | return (line_t) { | ||
| 29 | .p = (point_t){.x = a[0], .y = a[1], .z = a[2]}, | ||
| 30 | .v = (point_t){.x = a[3], .y = a[4], .z = a[5]} | ||
| 31 | }; | ||
| 32 | } | ||
| 33 | |||
| 34 | double det(double a, double b, double c, double d) { return a*d-b*c; } | ||
| 35 | |||
| 36 | bool parallel2d(line_t l1, line_t l2) { | ||
| 37 | double d = det(l1.v.x, l2.v.x, l1.v.y, l2.v.y); | ||
| 38 | return ABS(d) < eps; | ||
| 39 | } | ||
| 40 | |||
| 41 | point_t collide2d(line_t l1, line_t l2, double *t1, double *t2) { | ||
| 42 | double a1 = l1.v.x; | ||
| 43 | double b1 = -l2.v.x; | ||
| 44 | double c1 = l2.p.x - l1.p.x; | ||
| 45 | double a2 = l1.v.y; | ||
| 46 | double b2 = -l2.v.y; | ||
| 47 | double c2 = l2.p.y - l1.p.y; | ||
| 48 | |||
| 49 | double d = det(a1, b1, a2, b2); | ||
| 50 | *t1 = det(c1, b1, c2, b2) / d; | ||
| 51 | *t2 = det(a1, c1, a2, c2) / d; | ||
| 52 | |||
| 53 | double x = l1.p.x + l1.v.x * (*t1); | ||
| 54 | double y = l1.p.y + l1.v.y * (*t1); | ||
| 55 | |||
| 56 | return (point_t) {.x = x, .y = y}; | ||
| 57 | } | ||
| 58 | |||
| 59 | int main() { | ||
| 60 | for (n = 0; (buf = fgets(line, N, stdin)) != NULL; n++) | ||
| 61 | l[n] = readl(buf); | ||
| 62 | |||
| 63 | for (int i = 0; i < n; i++) { | ||
| 64 | for (int j = i+1; j < n; j++) { | ||
| 65 | if (parallel2d(l[i], l[j])) continue; | ||
| 66 | double t1, t2; | ||
| 67 | point_t p = collide2d(l[i], l[j], &t1, &t2); | ||
| 68 | if (t1 < -eps || t2 < -eps) continue; | ||
| 69 | s += p.x > XMIN-eps && p.x < XMAX+eps && | ||
| 70 | p.y > XMIN-eps && p.y < XMAX+eps; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | printf("%d\n", s); | ||
| 75 | return 0; | ||
| 76 | } | ||
diff --git a/2023/24/24b.c b/2023/24/24b.c new file mode 100644 index 0000000..3011108 --- /dev/null +++ b/2023/24/24b.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | Due to numerical errors, the result of this program was not correct on my | ||
| 3 | machine (ahah - doesn't work on my machine (: ) | ||
| 4 | However, with slightly different values for eps I got two answers whose | ||
| 5 | difference was 4 and one was too high, the other too low. A quick binary | ||
| 6 | search gave the correct result. | ||
| 7 | I'll make a more stable version if I feel like it. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <stdbool.h> | ||
| 11 | #include <stdio.h> | ||
| 12 | #include <stdlib.h> | ||
| 13 | |||
| 14 | #define D 10 | ||
| 15 | #define N 300 | ||
| 16 | |||
| 17 | #define ABS(x) ((x)>0?(x):-(x)) | ||
| 18 | #define eps 1e1 | ||
| 19 | #define EQ(x,y) (ABS((x)-(y))<eps) | ||
| 20 | |||
| 21 | typedef struct { double x, y, z; } point_t; | ||
| 22 | typedef struct { point_t p, v; } line_t; | ||
| 23 | |||
| 24 | char *buf, line[N]; | ||
| 25 | int nlines, s; | ||
| 26 | line_t l[N]; | ||
| 27 | |||
| 28 | bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; } | ||
| 29 | |||
| 30 | line_t readl(char *buf) { | ||
| 31 | double a[6]; | ||
| 32 | for (int i = 0; i < 6; i++) { | ||
| 33 | a[i] = (double)atoll(buf); | ||
| 34 | while (isnum(*buf)) buf++; | ||
| 35 | while (*buf != '\n' && !isnum(*buf)) buf++; | ||
| 36 | } | ||
| 37 | return (line_t) { | ||
| 38 | .p = (point_t){.x = a[0], .y = a[1], .z = a[2]}, | ||
| 39 | .v = (point_t){.x = a[3], .y = a[4], .z = a[5]} | ||
| 40 | }; | ||
| 41 | } | ||
| 42 | |||
| 43 | void swap(double *x, double *y) { double aux = *x; *x = *y; *y = aux; } | ||
| 44 | |||
| 45 | void printa(double A[D][D], double C[D], int d) { | ||
| 46 | for (int i = 0; i < d; i++) { | ||
| 47 | printf("[ "); | ||
| 48 | for (int j = 0; j < d; j++) | ||
| 49 | printf("%.2lf ", A[i][j]); | ||
| 50 | printf("]\t[%.2lf]\n", C[i]); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | /* Solve the linear system AX = C with row reduction */ | ||
| 55 | /* Return true if it has a unique solution, false in any other case */ | ||
| 56 | bool solvesystem(double A[D][D], double C[D], int d, double *X) { | ||
| 57 | /* Row reduction */ | ||
| 58 | for (int i = 0; i < d; i++) { | ||
| 59 | /* Make first nonzero */ | ||
| 60 | int nz; | ||
| 61 | for (nz = i; nz < d && EQ(A[i][nz], 0.0); nz++) ; | ||
| 62 | if (nz == d) return false; | ||
| 63 | swap(&C[i], &C[nz]); | ||
| 64 | for (int j = 0; j < d; j++) | ||
| 65 | swap(&A[i][j], &A[nz][j]); | ||
| 66 | |||
| 67 | /* Reduce rows */ | ||
| 68 | for (int ii = i+1; ii < d; ii++) { | ||
| 69 | double r = A[ii][i] / A[i][i]; | ||
| 70 | for (int k = i; k < d; k++) | ||
| 71 | A[ii][k] -= r*A[i][k]; | ||
| 72 | C[ii] -= r*C[i]; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /* Back substitution */ | ||
| 77 | for (int i = d-1; i >= 0; i--) { | ||
| 78 | X[i] = C[i]; | ||
| 79 | for (int j = i+1; j < d; j++) | ||
| 80 | X[i] -= A[i][j]*X[j]; | ||
| 81 | X[i] /= A[i][i]; | ||
| 82 | } | ||
| 83 | |||
| 84 | return true; | ||
| 85 | } | ||
| 86 | |||
| 87 | bool equal(point_t p, point_t q) { | ||
| 88 | return EQ(p.x, q.x) && EQ(p.y, q.y) && EQ(p.z, q.z); | ||
| 89 | } | ||
| 90 | |||
| 91 | point_t pos(line_t l, double t) { | ||
| 92 | return (point_t) { | ||
| 93 | .x = l.p.x + t*l.v.x, | ||
| 94 | .y = l.p.y + t*l.v.y, | ||
| 95 | .z = l.p.z + t*l.v.z | ||
| 96 | }; | ||
| 97 | } | ||
| 98 | |||
| 99 | void testsolution(line_t sol) { | ||
| 100 | for (int i = 0; i < nlines; i++) { | ||
| 101 | double t = -1.0; | ||
| 102 | if (!EQ(sol.v.x, l[i].v.x)) | ||
| 103 | t = (sol.p.x-l[i].p.x)/(l[i].v.x-sol.v.x); | ||
| 104 | if (!EQ(sol.v.y, l[i].v.y)) | ||
| 105 | t = (sol.p.y-l[i].p.y)/(l[i].v.y-sol.v.y); | ||
| 106 | if (!EQ(sol.v.z, l[i].v.z)) | ||
| 107 | t = (sol.p.z-l[i].p.z)/(l[i].v.z-sol.v.z); | ||
| 108 | point_t p1 = pos(sol, t), p2 = pos(l[i], t); | ||
| 109 | printf("Line %d intersected at t = %.2lf " | ||
| 110 | "in (%.2lf, %.2lf, %.2lf) and (%.2lf, %.2lf, %.2lf)\n", | ||
| 111 | i, t, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z); | ||
| 112 | if (t < eps || | ||
| 113 | !EQ(p1.x, p2.x) || !EQ(p1.y, p2.y) || !EQ(p1.z, p2.z)) { | ||
| 114 | printf("Error!\n"); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | printf("All lines intersected correctly, solution is valid\n"); | ||
| 119 | } | ||
| 120 | |||
| 121 | int main() { | ||
| 122 | for (nlines = 0; (buf = fgets(line, N, stdin)) != NULL; nlines++) | ||
| 123 | l[nlines] = readl(buf); | ||
| 124 | |||
| 125 | /* To figure the correct starting point + velocity, we solve some | ||
| 126 | * systems of linear equations. Write your starting point and velocity | ||
| 127 | * as unknowns x, y, z, Vx, Vy, Vz. Equating the position of the | ||
| 128 | * rock at time t1 (another unknown parameter) with the position | ||
| 129 | * of one of the hailstones at the same time t1, we get a system | ||
| 130 | * of 3 equations and 7 unknowns. Unfortunately, these equations | ||
| 131 | * have degree 2 - this is not a linear system! | ||
| 132 | * However, manipulating these equations a bit we can get a linear | ||
| 133 | * equation of the type: | ||
| 134 | * (Vy1-Vy2)x - (Vx1-Vx2)y + - (y1-y2)Vx + (x1-x2)Vy = | ||
| 135 | * y2Vx2 + x2Vy2 - y1Vx1 - x1Vy1 | ||
| 136 | * Where x1, y1, z2, Vx1, Vy1, Vz1 and x2, y2, z2, Vx2, Vy2, Vz2 | ||
| 137 | * are the starting points and velocities of two of the hailstones. | ||
| 138 | * So with 2 lines we can get a linear equation. Similarly, we can | ||
| 139 | * get equations involving the unknowns z and Vz. | ||
| 140 | * We can use the myriad of hailstones we have to generate as many | ||
| 141 | * equations as we like. The system is going to be overdetermined, | ||
| 142 | * but the problem statement seems to ensure that there is going to | ||
| 143 | * be a solution. On the other hand it can happen that we make a | ||
| 144 | * bad choice of lines and the equation we use are underdetermined. | ||
| 145 | * This last problem is not accounted for in the code - if it happens, | ||
| 146 | * one can shuffle the input file until it works. | ||
| 147 | */ | ||
| 148 | int d = 6; | ||
| 149 | double A[D][D] = { | ||
| 150 | /* First equation: lines 0 and 1, x and y only */ | ||
| 151 | {l[0].v.y-l[1].v.y, l[1].v.x-l[0].v.x, 0.0, | ||
| 152 | l[1].p.y-l[0].p.y, l[0].p.x-l[1].p.x, 0.0}, | ||
| 153 | /* Second equation: lines 0 and 2, x and y only */ | ||
| 154 | {l[0].v.y-l[2].v.y, l[2].v.x-l[0].v.x, 0.0, | ||
| 155 | l[2].p.y-l[0].p.y, l[0].p.x-l[2].p.x, 0.0}, | ||
| 156 | /* Third equation: lines 0 and 1, x and z only */ | ||
| 157 | {l[0].v.z-l[1].v.z, 0.0, l[1].v.x-l[0].v.x, | ||
| 158 | l[1].p.z-l[0].p.z, 0.0, l[0].p.x-l[1].p.x}, | ||
| 159 | /* Fourth equation: lines 0 and 2, x and z only */ | ||
| 160 | {l[0].v.z-l[2].v.z, 0.0, l[2].v.x-l[0].v.x, | ||
| 161 | l[2].p.z-l[0].p.z, 0.0, l[0].p.x-l[2].p.x}, | ||
| 162 | /* Fifth equation: lines 0 and 1, y and z only */ | ||
| 163 | {0.0, l[0].v.z-l[1].v.z, l[1].v.y-l[0].v.y, | ||
| 164 | 0.0, l[1].p.z-l[0].p.z, l[0].p.y-l[1].p.y}, | ||
| 165 | /* Sixth equation: lines 0 and 2, y and z only */ | ||
| 166 | {0.0, l[0].v.z-l[2].v.z, l[2].v.y-l[0].v.y, | ||
| 167 | 0.0, l[2].p.z-l[0].p.z, l[0].p.y-l[2].p.y}, | ||
| 168 | }; | ||
| 169 | double C[D] = { | ||
| 170 | /* First equation: lines 0 and 1, x and y only */ | ||
| 171 | l[1].p.y*l[1].v.x - l[1].p.x*l[1].v.y | ||
| 172 | - l[0].p.y*l[0].v.x + l[0].p.x*l[0].v.y, | ||
| 173 | /* Second equation: lines 0 and 2, x and y only */ | ||
| 174 | l[2].p.y*l[2].v.x - l[2].p.x*l[2].v.y | ||
| 175 | - l[0].p.y*l[0].v.x + l[0].p.x*l[0].v.y, | ||
| 176 | /* Third equation: lines 0 and 1, x and z only */ | ||
| 177 | l[1].p.z*l[1].v.x - l[1].p.x*l[1].v.z | ||
| 178 | - l[0].p.z*l[0].v.x + l[0].p.x*l[0].v.z, | ||
| 179 | /* Fourth equation: lines 0 and 2, x and z only */ | ||
| 180 | l[2].p.z*l[2].v.x - l[2].p.x*l[2].v.z | ||
| 181 | - l[0].p.z*l[0].v.x + l[0].p.x*l[0].v.z, | ||
| 182 | /* Fifth equation: lines 0 and 1, y and z only */ | ||
| 183 | l[1].p.z*l[1].v.y - l[1].p.y*l[1].v.z | ||
| 184 | - l[0].p.z*l[0].v.y + l[0].p.y*l[0].v.z, | ||
| 185 | /* Sixth equation: lines 0 and 2, y and z only */ | ||
| 186 | l[2].p.z*l[2].v.y - l[2].p.y*l[2].v.z | ||
| 187 | - l[0].p.z*l[0].v.y + l[0].p.y*l[0].v.z, | ||
| 188 | }; | ||
| 189 | double X[d]; | ||
| 190 | if (!solvesystem(A, C, d, X)) { | ||
| 191 | printf("No unique solution, shuffle input and try again.\n"); | ||
| 192 | exit(1); | ||
| 193 | } | ||
| 194 | |||
| 195 | line_t sol = { | ||
| 196 | .p = {.x = X[0], .y = X[1], .z = X[2]}, | ||
| 197 | .v = {.x = X[3], .y = X[4], .z = X[5]} | ||
| 198 | }; | ||
| 199 | testsolution(sol); | ||
| 200 | |||
| 201 | printf("p = (%.2lf, %.2lf, %.2lf), v = (%.2lf, %.2lf, %.2lf)\n", | ||
| 202 | sol.p.x, sol.p.y, sol.p.z, sol.v.x, sol.v.y, sol.v.z); | ||
| 203 | printf("%lf\n", sol.p.x + sol.p.y + sol.p.z); | ||
| 204 | return 0; | ||
| 205 | } | ||
