Codeforces: Empty Triangle

  这是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.

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



转载于:https://www.cnblogs.com/LyonLys/archive/2012/09/12/cf_empty_triangle_Lyon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值