极角排序+求锐角三角形个数——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
*/

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12333633.html
今日推荐