极角排序+求锐角三角形个数——uva12123

这个版本还不能处理三点共线的情况(处理起来其实比较麻烦)

可以用atan2来排序(较为简单,但是精度误差大),也可以用叉积排序(比较优秀)

atan2

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int maxn = 1250;
const double pi = acos(-1.0);
const double eps = 1e-10;

struct point{
    double x,y;
}p[maxn];
double s[maxn*2];

int main()
{
    //freopen("input.txt" , "r" , stdin);
    int N , cas = 1;
    while(scanf("%d" ,&N)!=EOF && N){

        for(int i=0;i<N;i++)
            scanf("%lf%lf" , &p[i].x , &p[i].y);
        LL obtuse = 0;
        for(int i=0;i<N;i++){
            if(i) swap(p[i] , p[0]);
            for(int k=1;k<N;k++) s[k] = atan2(p[k].y-p[0].y , p[k].x-p[0].x);
            sort(s+1 , s+N);
            for(int k=1;k<N;k++) s[k+N-1] = s[k] + 2*pi;

            int k=1 , e1=1 , e2=1;
            for(; k<N; k++){
                while(s[e1] - s[k] - 0.5*pi < -eps) e1++;
                while(s[e2] - s[k] <= pi) e2++;
                obtuse += e2 - e1;
            }
        }
        LL ans = N*(N-1)*(N-2)/6 - obtuse;
        printf("Scenario %d:\n" , cas++);
        printf("There are %lld sites for making valid tracks\n" , ans);
    }
    return 0;
}

叉积

/*
极角排序:定义极角大小顺序是3412象限
求锐角三角形个数/总面积(可能三点共线)
    总三角形-直角三角形-钝角三角形=C(n,3)-直角个数-钝角个数
    以每个点为源点,级角排序,然后双指针扫一次求直角钝角个数
*/
#include<bits/stdc++.h>
using namespace std;
#define N 4005
typedef double db;
const db eps=1e-6;
const db pi=acos(-1);
int sign(db k){if (k>eps) return 1; else if (k<-eps) return -1; return 0;}
int cmp(db k1,db k2){return sign(k1-k2);}

struct point{
    db x,y;
    point(){}
    point(db x,db y):x(x),y(y){}
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
    point operator * (db k1) const{return (point){x*k1,y*k1};}
    point operator / (db k1) const{return (point){x/k1,y/k1};}
    int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
};
db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;}
db rad(point k1,point k2){return atan2(cross(k1,k2),dot(k1,k2));}
int comp(point k1,point k2){
    if(k1.getP()==k2.getP())return sign(cross(k1,k2))>0;
    return k1.getP()<k2.getP();
}

int n,ans;
point pp[N],p[N],O;

int main(){
    int tt=0;
    while(cin>>n && n){
        ++tt;
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        ans=n*(n-1)*(n-2)/6;

        long long sum=0;
        for(int i=1;i<=n;i++){
            O=p[i];
            int tot=0;
            for(int j=1;j<=n;j++)
                if(j!=i)pp[++tot]=p[j]-O;
            sort(pp+1,pp+1+tot,comp);
            for(int j=1;j<=tot;j++)
                pp[j+tot]=pp[j];

            int p1=1,p2=1;
            for(int j=1;j<=tot;j++){
                //p1的夹角[0,pi/2)
                while(p1+1<j+tot && sign(cross(pp[j],pp[p1+1]))>=0 && sign(dot(pp[j],pp[p1+1]))>0)
                    p1++;
                //p2的夹角[0,pi]
                while(p2+1<j+tot && sign(cross(pp[j],pp[p2+1]))>=0)
                    p2++;
                sum+=p2-p1;
            }
        }
        printf("Scenario %d:\n",tt);
        printf("There are %d sites for making valid tracks\n",ans-sum);
    }
}
/*
6
26 23
51 94
103 110
164 107
116 67
73 16
*/

原文地址:https://www.cnblogs.com/zsben991126/p/12333633.html

时间: 2024-10-17 05:59:30

极角排序+求锐角三角形个数——uva12123的相关文章

Wall--POJ1113(极角排序+求凸包)

http://poj.org/problem?id=1113 题目大意:现在要给n个点,让你修一个围墙把这些点围起来,距离最小是l 分析  :现在就是求凸包的周长然后再加上一个圆的周长 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<algorithm> #include<iostream> #include<qu

POJ 2388 Who&#39;s in the Middle(水~奇数个数排序求中位数)

题目链接:http://poj.org/problem?id=2388 题目大意: 奇数个数排序求中位数 解题思路:看代码吧! AC Code: 1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)!=EOF) 8 { 9 int na[n+1]; 10 for(int i=0; i

10.1 叉积 ,极角排序,扫描法求凸包

凸包:用一个凸多边形将所有点围起来,这个凸多边形就是凸包 1.先要引入一个数学工具,向量叉积   |c|=|a×b|=|a| |b|sinα   (α为a,b向量之间的夹角) 则 |c| 为向量a ,b所组成的平行四边形的面积 这里是用叉积判断两向量的相对位置关系(非常有用!) 则 a x b < 0 (a在b的逆时针方向 ) , b x a > 0(b在a的顺时针方向) //求叉积 struct node{ double x ,y; node operator -( const node &

hdu-5784 How Many Triangles(计算几何+极角排序)

题目链接: How Many Triangles Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 570    Accepted Submission(s): 183 Problem Description Alice has n points in two-dimensional plane. She wants to know ho

1606 - Amphiphilic Carbon Molecules(极角排序)

这道题的关键是用到了极角排序的方法,枚举一个固定点,其他点以此点为原心求出角度,然后排序,将数点的多少转化为数角度的多少.因为角度是有序的,便可以用一次扫描求出最大值.另外,还用到了一个小技巧,那就是利用对称性,将一侧的黑点转化成另一侧的白点,这样只需要数白点的个数就好了. 值得注意的是,为了形成那条分界线,我们枚举两个角度(也就是由基准点为原心的新坐标系中的点)   ,使他们之间的夹角不超过180°,为了使分界线旋转360°,我们将l变量枚举到最后一个点再停,所以r变量的自加变成了(r+1)%

【极角排序、扫描线】UVa 1606 - Amphiphilic Carbon Molecules(两亲性分子)

Shanghai Hypercomputers, the world's largest computer chip manufacturer, has invented a new class of nanoparticles called Amphiphilic Carbon Molecules (ACMs). ACMs are semiconductors. It means that they can be either conductors or insulators of elect

BZOJ 1132 [POI2008]Tro(极角排序)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1132 [题目大意] 平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和(N<=3000) [题解] 我们发现直接枚举三个点计算会造成很大部分的叉积重复被计算, 因此我们枚举i,计算pj和pi点差的后缀和,我们发现对于固定边ij, 其与后面的枚举量相关贡献就为pj-pi和点差后缀和的叉积. 因此我们针对每个i进行后面数据的极角排序,O(n)计算与i相关的所有答案贡献. [代码]

[POJ2007]Scrambled Polygon(计算几何 极角排序)

题目链接:http://poj.org/problem?id=2007 题意:给出凸包和起点,逆序输出. 极角排序可以用反三角函数求出角度,按照角度排序.也可以用叉乘来做.注意题目说给定第一个数据是0,0,这是凸包的起点,数据中有在x轴负半轴的数据,所以排序的时候0,0要跳过.只排1~n-1个坐标. 1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstri

极角排序详解

关于极角排序: 在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向). 对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从Ox到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标. 那么给定平面上的一些点,把它们按照一个选定的中心点排成顺(逆)时针. 极角排序常用的四种方法: 在说四种方法之前,给出一会用到的函数和存储点的结构体 struct point//存储点 { double x