In this directory, I have my presentation in TrianglesContainOrigin.odp, converted to PDF in TrianglesContainOrigin.pdf.
Below is the commented code (src/make_jgraph.cpp) which creates the jgraph in the presentation, and also solves the problem in the fastest way:
/* TrianglesContainOrigin/src/make_jgraph.cpp
James S. Plank
September, 2020.
This program takes input to the TrianglesContainOrigin Topcoder problem on
standard input, and then draws the jgraph which can help you visualize a solution.
It then solves the problem and prints it as a comment on the last line in the
jgraph file.
*/
#include <string>
#include <vector>
#include <cmath>
#include <map>
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
/* Bundling up all of my information in this data structure makes the problem easier. */
class Point {
public:
double x; // The point's x value
double y; // The point's x value
double angle; // The point's angle from the origin (radians)
int index; // The point's number in the Points vector, which is sorted by angle.
};
int main()
{
double hyp, a; // Hypotenuse, angle
double pi; // Convenient to have pi in a variable
map <double, Point *> m; // Map of points sorted by angle
vector <Point *> points; // Vector of points sorted by angle
vector <string> colors; // This is to draw the colored regions.
long long num; // The number of triangles
int i; // Temporary variable
int p1, p2, p3, p4; // These match the presentation
double dx, dy;
Point *p;
map <double, Point *>::iterator mit;
const char *c;
/* Set pi, and put two colors (pink, blue) into colors */
pi = acos(-1.0);
colors.push_back("1 .7 .7");
colors.push_back(".7 1 1");
/* Read the points, calculate their angles from the origin and put them into the map */
while (cin >> dx >> dy) {
p = new Point;
p->x = dx;
p->y = dy;
hyp = sqrt(dx*dx + dy*dy);
p->angle = acos(dx/hyp);
if (dy < 0) p->angle = 2 * pi - p->angle;
m[p->angle] = p;
}
/* Now calculate their indices, and make the points array, sorted by angle. */
for (mit = m.begin(); mit != m.end(); mit++) {
p = mit->second;
p->index = points.size();
points.push_back(p);
}
/* Draw the jgraph axes */
printf("newgraph\n");
printf("xaxis min -10000 max 10000 size 6 nodraw\n");
printf("yaxis min -10000 max 10000 size 6 nodraw\n");
printf("clip\n");
/* Draw the colored regions opposite each adjacent pair of points.
If there are an odd number of points, make the first region light
green, and alternate blue/pink for the others (I do this because
otherwise the first and last regions are the same color). */
printf("\n(*Draw the colored regions *)\n\n"); // This is handy when you want to look
// at the jgraph.
for (i = 0; i < (int) points.size(); i++) {
p = points[i];
a = p->angle + pi;
if (i == 0 && points.size()%2 == 1) {
c = ".5 1 .5";
} else {
c = colors[i%colors.size()].c_str();
}
/* Multiplying by 100,000 means that points of the triangle will be outside of
the axes. By specifying "clip" above, anything outside of the axes won't
be drawn. */
printf("newline color %s poly pcfill %s pts %lg %lg 0 0 ",
c, c,
100000 * cos(a),
100000 * sin(a));
p = points[(i+1)%points.size()];
a = p->angle + pi;
printf("%lg %lg\n", 100000 * cos(a), 100000 * sin(a));
}
printf("\n(*Draw the lines from the origin to each point *)\n\n");
for (i = 0; i < (int) points.size(); i++) {
printf("newline pts 0 0 %lg %lg\n", points[i]->x, points[i]->y);
}
printf("\n(*Draw the points *)\n\n");
printf("newcurve marktype circle pts\n");
for (i = 0; i < (int) points.size(); i++) {
printf(" %lg %lg\n", points[i]->x, points[i]->y);
}
printf("\n(*Draw the origin *)\n\n");
printf("newcurve marktype box color 1 0 0 pts 0 0\n");
printf("\n(*Draw the labels if there are <= 26 points *)\n\n");
if (points.size() <= 26) {
for (i = 0; i < (int) points.size(); i++) {
p = points[i];
printf("newstring fontsize 14 hjc vjc x %lg y %lg : %c\n",
p->x + cos(p->angle)*500,
p->y + sin(p->angle)*500,
'A'+i);
}
}
/* Do the calculation in the fastest way */
/* Put a big ol sentinel onto the array. */
p = new Point;
p->x = 0;
p->y = 0;
p->angle = 4*pi; /* Actually, 3*pi will do */
p->index = points.size();
points.push_back(p);
/* Now, enumerate p1 and p2, and incrementally calculate p3 and p4, and keep
adding the number of points between p3 and p4 to the answer. */
num = 0;
p3 = 0;
for (p1 = 0; p1 < (int) points.size()-1; p1++) {
while (points[p3]->angle <= points[p1]->angle + pi) p3++;
p4 = p3;
for (p2 = p1+1; p2 < p3; p2++) {
while (points[p4]->angle <= points[p2]->angle + pi) p4++;
num += (points[p4]->index - points[p3]->index);
}
}
printf("\n(*Number of triangles: %lld. *)\n", num);
return 0;
}
|