• 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



  • 相关阅读:
    tlb、tlh和tli文件的关系
    String算法
    Reverse A String by STL string
    windows内存管理复习(加深了理解得很!)
    [转载]有关DLL中New和外部Delete以以及跨DLL传递对象的若干问题
    顺势工作时间
    C++箴言:绝不在构造或析构期调用虚函数
    inline函数复习
    从编译器的角度更加深入考虑封装的使用
    复习:constructor和destructor的compiler实现
  • 原文地址:https://www.cnblogs.com/LyonLys/p/cf_empty_triangle_Lyon.html
Copyright © 2020-2023  润新知