aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2023/24/24a.c76
-rw-r--r--2023/24/24b.c205
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
12typedef struct { double x, y, z; } point_t;
13typedef struct { point_t p, v; } line_t;
14
15char *buf, line[N];
16int n, s;
17line_t l[N];
18
19bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; }
20
21line_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
34double det(double a, double b, double c, double d) { return a*d-b*c; }
35
36bool 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
41point_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
59int 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/*
2Due to numerical errors, the result of this program was not correct on my
3machine (ahah - doesn't work on my machine (: )
4However, with slightly different values for eps I got two answers whose
5difference was 4 and one was too high, the other too low. A quick binary
6search gave the correct result.
7I'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
21typedef struct { double x, y, z; } point_t;
22typedef struct { point_t p, v; } line_t;
23
24char *buf, line[N];
25int nlines, s;
26line_t l[N];
27
28bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; }
29
30line_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
43void swap(double *x, double *y) { double aux = *x; *x = *y; *y = aux; }
44
45void 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 */
56bool 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
87bool 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
91point_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
99void 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
121int 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}

Generated with cgit - Back to sebastiano.tronto.net