• HDU 5784 (计算几何)


    Problem How Many Triangles (HDU 5784)

    题目大意

      给定平面上的n个点(n《2000),询问可以组成多少个锐角三角形。

    解题分析

      直接统计锐角三角形较困难,考虑问题的反面,统计直角三角形、钝角三角形、平角三角形(暂时这么叫吧QAQ)。

      首先枚举三角形的一个端点A,对其他点进行象限为第一关键字,极角为第二关键字排序。

      然后使用三个指针,进行O(n)的扫描。

      具体做法为用 i 指针指向三角形的第二个端点B。我们可以假想通过平移和旋转,把A点置于平面直角坐标系的原点,把B点置于x轴的正方向。那么可以与AB组成钝角或直角的点就在三四象限或者y轴。

      将 j 指针指向第一象限内可以组成锐角的最靠后的点,将k指针从j + 1 开始扫描至最后一个可以组成钝角的点,然后统计对答案的贡献。

      之后将 i 指针 +1,继续扫描。

      注意一些特殊的情况,可以写个暴力对拍,造点小数据debug。

    参考程序

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 #define eps 1e-8
     7 
     8 struct P{
     9     long long x,y;
    10     int f;
    11     friend P operator -(P a,P b){
    12         return (P){a.x-b.x,a.y-b.y};
    13     }
    14 }a[20008],b[20008],S;
    15 
    16 int n,m;
    17 
    18 inline long long cross(P a,P b,P c){  //ab X ac
    19     return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
    20 }
    21 
    22 inline int calc(P a){
    23     if (a.x>0 && a.y==0) return 1;
    24     if (a.x>0 && a.y>0) return 1;
    25     if (a.x==0 && a.y>0) return 2;
    26     if (a.x<0 && a.y>0) return 2;
    27     if (a.x<0 && a.y==0) return 3;
    28     if (a.x<0 && a.y<0) return 3;
    29     if (a.x==0 && a.y<0) return 4;
    30     if (a.x>0 && a.y<0) return 4;
    31 }
    32 
    33 inline bool cmp(const P a,const P b) {
    34     if (a.f<b.f) return true;
    35     if (a.f>b.f) return false;
    36     long long tmp=cross(S,a,b);
    37     if (tmp>0) return true;
    38     return false; 
    39 }
    40 
    41 inline bool ok(P a,P b,P c){
    42     long long tmp=(b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
    43     if (tmp>0) return true;
    44     return false;
    45 }
    46 
    47 int main(){
    48     while (~scanf("%d",&n)){
    49         for (int i=1;i<=n;i++) scanf("%I64d %I64d",&a[i].x,&a[i].y);
    50         long long sum=0;
    51         for (int ii=1;ii<=n;ii++){
    52             S=a[ii]; m=0; 
    53             for (int j=1;j<=n;j++)
    54                 if (j!=ii) b[++m]=a[j];
    55             for (int i=1;i<=m;i++) b[i].f=calc(b[i]-S);
    56             sort(b+1,b+m+1,cmp);
    57             int i=1,j=1,k=1;
    58             while (ok(S,b[i],b[j]) && cross(S,b[i],b[j])>=0 && j<=m) j++;
    59             if (j==m+1) continue;
    60             j--; k=j+1;
    61             while (i<=m)
    62             {
    63                 if (!ok(S,b[i],b[k])){        
    64                     while (!ok(S,b[i],b[k+1]) && k<m) k++;
    65                     sum+=k-j;
    66                 }
    67                 i++;
    68                 if (j<i) j=i; 
    69                 while (ok(S,b[i],b[j+1]) && cross(S,b[i],b[j+1])>0 && j<m) j++;
    70                 if (k<=j) k=j+1;
    71                 if (k>m) break;
    72             }        
    73         }
    74         long long p=1ll*n*(n-1)*(n-2)/6;
    75         printf("%I64d
    ",p-sum);
    76     }
    77 }
    View Code
  • 相关阅读:
    列表基本操作——1
    条件判断与嵌套
    数据拼接与数据转换
    变量与赋值
    打印数与type()函数
    print()函数与打印字符串
    arduino开发ESP8266学习笔记二----按键控制LED灯
    arduino开发ESP8266学习笔记一 ----点亮一个LED灯
    无线充电
    EMC设计总结
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/5730475.html
Copyright © 2020-2023  润新知