这是codeforces gym中的2011-2012 Stanford Local Contest, 8 October, 2011的一道几何题。题意很简单,就是给出500条直线,问你有多少个不被其他直线穿过的三角形。这道题一个很简单的思路就是先要找出每条直线上的交点,因为如果图形是空三角形,那么组成三角形的的每两个顶点都是某条直线上相邻的两个交点。于是我们利用直线的标号,用某条直线上所有点相邻的两条直线与该直线组成三角形,很容易可以找到最多不超过250000个三角形。其中必然会有重复的三角形。如果三角形重复次数是3(最多也只能是3),那么这个就是一个空三角形。用multiset可以很方便的统计重复次数,或者用hash统计也可以。不过现在想到,好像直接make完pair以后排个序直接统计就好了。。囧!
题目如下:
Empty Triangles
Problem Description
Do you know how easy it is to make a very simple problem into a brutally hard one? Here is an example. How many triangles can you make with N straight lines in the plane? As long as they have different slopes and no three of them meet at a single point, there will be triangles, which is the maximum possible you can get.
Okay, that wasn't too bad. But let's see what happens if we only count triangles that are empty (that is, none of the lines pass through the interior of the triangle). Then, the number of triangles suddenly becomes very small. For example, with 4 straight lines, we can only make 2 empty triangles, whereas the total number of triangles can be as big as 4. Refer to the diagram.
In fact, a general formula for the maximum number of empty triangles that can be drawn with N lines is not known. The hard part, however, is to find the right configuration of the lines. Your job is much easier; given N straight lines on the plane, count the number of empty triangles.
Okay, that wasn't too bad. But let's see what happens if we only count triangles that are empty (that is, none of the lines pass through the interior of the triangle). Then, the number of triangles suddenly becomes very small. For example, with 4 straight lines, we can only make 2 empty triangles, whereas the total number of triangles can be as big as 4. Refer to the diagram.
In fact, a general formula for the maximum number of empty triangles that can be drawn with N lines is not known. The hard part, however, is to find the right configuration of the lines. Your job is much easier; given N straight lines on the plane, count the number of empty triangles.
Input
The input consists of multiple test cases. Each test case begins with a line containing an integer N, 1 ≤ N ≤ 500, which indicates the number of lines on the plane. The next N lines each contain four integers x1, y1, x2, and y2 (between -1000 and 1000), representing a straight line that goes through (x1, y1) and (x2, y2). It is guaranteed that no three lines meet at the same point, and all the lines are distinct. The input terminates with a line with N = 0.
Output
For each test case, print out a single line that contains the number of empty triangles formed by the given lines.
Sample Input
4 0 0 1 2 0 0 -1 2 1 0 1 1 -1 0 -1 -1 5 0 0 1 0 0 1 1 1 0 2 1 2 0 3 1 3 0 4 1 4 0
Sample Output
2 0
这是3400ms+通过的代码:
View Code
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <algorithm> 5 #include <set> 6 #include <cassert> 7 #include <vector> 8 9 #define feq(a, b) (fabs((a) - (b)) < eps) 10 11 using namespace std; 12 13 typedef pair<int, int> pii; 14 typedef pair<pii, int> piii; 15 typedef vector<double> vdb; 16 typedef vector<int> vi; 17 18 const int maxn = 505; 19 const double eps = 1e-6; 20 const int mod = 1000007; 21 22 int hash[mod][3], cnt[mod]; 23 //multiset<piii> cnt; 24 25 bool judge(int *a, int *b){ 26 for (int i = 0; i < 3; i++){ 27 if (a[i] != b[i]) return true; 28 } 29 return false; 30 } 31 32 bool insert(int *a){ 33 int p = ((a[0] << 16) + (a[1] << 8) + a[2]) % mod; 34 35 if (p < 0){ 36 p += mod; 37 } 38 while (judge(hash[p], a) && cnt[p]) p = (p + 1) % mod; 39 for (int i = 0; i < 3; i++){ 40 hash[p][i] = a[i]; 41 } 42 cnt[p]++; 43 if (cnt[p] == 3) return true; 44 return false; 45 } 46 47 struct point{ 48 int id; 49 double x, y; 50 bool operator < (const point &a) const{ 51 if (feq(x, a.x)) return y < a.y; 52 return x < a.x; 53 } 54 }; 55 56 struct Line{ 57 point a, b; 58 vector<point> cross; 59 void fix(){ 60 sort(&cross[0], &cross[0] + cross.size()); 61 } 62 }line[maxn]; 63 64 bool parallel(Line u, Line v){ 65 return feq((u.a.x - u.b.x) * (v.a.y - v.b.y), (v.a.x - v.b.x) * (u.a.y - u.b.y)); 66 } 67 68 point ll_inst(Line l1, Line l2){ 69 point ans = l1.a; 70 double t = ((l1.a.x - l2.a.x) * (l2.a.y - l2.b.y) - (l1.a.y - l2.a.y) * (l2.a.x - l2.b.x)) 71 / ((l1.a.x - l1.b.x) * (l2.a.y - l2.b.y) - (l1.a.y - l1.b.y) * (l2.a.x - l2.b.x)); 72 73 ans.x += (l1.b.x - l1.a.x) * t; 74 ans.y += (l1.b.y - l1.a.y) * t; 75 76 return ans; 77 } 78 79 int id[3]; 80 81 int main(){ 82 int n; 83 point tmp; 84 85 while (~scanf("%d", &n) && n){ 86 //cnt.clear(); 87 memset(cnt, 0, sizeof(cnt)); 88 for (int i = 0; i < n; i++){ 89 line[i].cross.clear(); 90 scanf("%lf%lf%lf%lf", &line[i].a.x, &line[i].a.y, &line[i].b.x, &line[i].b.y); 91 for (int j = 0; j < i; j++){ 92 if (parallel(line[i], line[j])) continue; 93 tmp = ll_inst(line[i], line[j]); 94 tmp.id = j; 95 line[i].cross.push_back(tmp); 96 tmp.id = i; 97 line[j].cross.push_back(tmp); 98 } 99 } 100 for (int i = 0; i < n; i++){ 101 line[i].fix(); 102 } 103 104 int out = 0; 105 106 for (int i = 0; i < n; i++){ 107 int endj = line[i].cross.size(); 108 109 for (int j = 1; j <endj; j++){ 110 id[0] = i; 111 id[1] = line[i].cross[j - 1].id; 112 id[2] = line[i].cross[j].id; 113 sort(id, id + 3); 114 //cnt.insert(make_pair(make_pair(id[0], id[1]), id[2])); 115 if (insert(id)) out++; 116 } 117 } 118 /* 119 multiset<piii>::iterator ii; 120 piii pre = make_pair(make_pair(-1, -1), -1); 121 122 for (ii = cnt.begin(); ii != cnt.end(); ii++){ 123 piii tt = (*ii); 124 125 if (tt == pre){ 126 pre = tt; 127 continue; 128 } 129 pre = tt; 130 if (cnt.count(tt) == 3){ 131 //printf("%d %d %d\n", tt.first.first, tt.first.second, tt.second); 132 out++; 133 } 134 } 135 */ 136 /* 137 for (int i = 0; i < mod; i++){ 138 if (cnt[i] == 3) out++; 139 } 140 */ 141 printf("%d\n", out); 142 } 143 144 return 0; 145 }
——written by Lyon