User:Sweepline/UVa 10979.cpp

/* * Solution for problem #10979 'How Many Triangles?' * * O(n^5) algorithm: constructs a graph from segments and * counts 3-cliques in it. */ using namespace std;
 * 1) include
 * 2) include
 * 3) include
 * 4) include
 * 5) include
 * 6) define EPS 1e-9

struct Point { double x, y;	Point(double x=0, double y=0) : x(x), y(y) {} };

bool operator <(const Point &a, const Point &b) {	return a.x? s.B.x) + EPS && (s.A.y <? s.B.y) - EPS < r.y && r.y < (s.A.y >? s.B.y) + EPS; }

/* Determines point of intersection of two line segments. */ int isect(Point &r, Segment s, Segment t) { double d = s.a * t.b - s.b * t.a;	if (fabs(d) < EPS) return 0; r = Point((s.c * t.b - s.b * t.c) / d, (s.a * t.c - s.c * t.a) / d); return onseg(r, s) && onseg(r, t); }

/* Determines whether the line segments overlap (i.e. are parallel and share  at least one point), and if so, replaces s with their union. */ int overlap(Segment &s, Segment t) { if (fabs(s.a * t.b - s.b * t.a) > EPS) return 0; if (onseg(t.A, s) && onseg(t.B, s)) return 1; if (onseg(s.A, t) && onseg(s.B, t)) { s = t; return 1; } if (onseg(s.B, t)) swap(s.A, s.B); if (!onseg(s.A, t)) return 0; if (onseg(t.B, s)) swap(t.A, t.B); if (!onseg(t.A, s)) return 0; s = Segment(s.B, t.B); return 1; }

int main {	vector S;	vector V;	int adj[128][128], i, j, k, n;

while (scanf("%d", &n) == 1) { S.clear; while (n-- > 0) { double x1, y1, x2, y2; scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2); S.push_back(Segment(Point(x1,y1), Point(x2,y2))); }

/* First, make sure that no two line segments overlap */ do { k = 0; for (i = 0; i < S.size; i++) for (j = i+1; j < S.size; j++) if (overlap(S[i], S[j])) { S.erase(S.begin + j--); k++; }		} while (k);

/*		 * We'll build a graph from given line segments. * The set of vertices (V) are segments' endpoints and points * of intersections. Edges are parts of given line segments. */

V.clear; for (i = 0; i < S.size; i++) { V.push_back(S[i].A); V.push_back(S[i].B); for (j = 0; j < i; j++) { Point r;				if (isect(r, S[i], S[j])) V.push_back(r); }		}		sort(V.begin, V.end); V.erase(unique(V.begin, V.end), V.end);

/*		 * Now we'll fill the adjacency matrix. * We'll also count number of triangles, whose all vertices * lie on the same line. */		n = 0; memset(adj, 0, sizeof(adj)); for (i = 0; i < S.size; i++) { /* Find all points, which lie on i-th segments */ vector P;			for (j = 0; j < V.size; j++) if (onseg(V[j], S[i])) P.push_back(j);

/*			 * Number of triangles with vertices on this segment * is simply the binomial coeficient (k choose 3), * where k is the total number of points on segment. */			k = P.size; n -= k*(k-1)*(k-2)/6;

/* Join every pair of points with an edge in the graph. */			for (j = 0; j < P.size; j++) for (k = 0; k < P.size; k++) adj[P[j]][P[k]] = 1; }

/* Finally, just find the number of 3-cliques in the graph. */		for (i = 0; i < V.size; i++) for (j = i+1; j < V.size; j++) if (adj[i][j]) for (k = j+1; k < V.size; k++) n += adj[j][k] & adj[k][i];

printf("%d\n", n); }

return 0; }