这个版本还不能处理三点共线的情况(处理起来其实比较麻烦)
可以用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: " , cas++); printf("There are %lld sites for making valid tracks " , 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: ",tt); printf("There are %d sites for making valid tracks ",ans-sum); } } /* 6 26 23 51 94 103 110 164 107 116 67 73 16 */