题意:给你N个点,让你选四个点组成凸多边形,求总的方法数
详细解释:http://blog.sina.com.cn/s/blog_64675f540100ksug.html
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #include<stdlib.h> 7 #include<queue> 8 #include<map> 9 #include<algorithm> 10 using namespace std; 11 const double eps = 1e-12; 12 const double pi = acos(-1.0); 13 const double INF = 10001000; 14 double sqr(double x){ 15 return x*x; 16 } 17 int cmp(double x){ 18 if(fabs(x)<eps) return 0; 19 if(x>0) return 1; 20 return -1; 21 } 22 struct point{ 23 double x,y; 24 int index; 25 point(){} 26 point(double a,double b):x(a),y(b){} 27 void input(){ 28 scanf("%lf%lf",&x,&y); 29 } 30 double angle() { 31 return atan2(y, x); 32 } 33 friend point operator + (const point &a,const point &b){ 34 return point(a.x+b.x,a.y+b.y); 35 } 36 friend point operator - (const point &a,const point &b){ 37 return point(a.x-b.x,a.y-b.y); 38 } 39 friend bool operator == (const point &a,const point &b){ 40 return (cmp(a.x-b.x)==0)&&(cmp(a.y-b.y))==0; 41 } 42 friend point operator * (const point &a,double b){ 43 return point(a.x*b,a.y*b); 44 } 45 friend point operator / (const point &a,double b){ 46 return point(a.x/b,a.y/b); 47 } 48 friend double operator ^ (const point &a,const point &b) 49 { 50 return a.x*b.y - a.y*b.x; 51 } 52 double operator *(const point &b)const 53 { 54 return x*b.x + y*b.y; 55 } 56 double norm(){ //向量的模长 57 return sqrt(sqr(x)+sqr(y)); 58 } 59 }; 60 61 double det(const point &a,const point &b){ //向量的叉集 62 return a.x*b.y-a.y*b.x; 63 } 64 double dot(const point &a,const point &b){ //向量的点集 65 return a.x*b.x+a.y*b.y; 66 } 67 double dot(const point &a,const point &b,const point &c){ //向量的点集ba 到bc 68 return dot(a-b,c-b); 69 } 70 double dist(const point &a,const point &b){ //两点间的距离 71 return (a-b).norm(); 72 } 73 point rotate_point(const point &p,double A){ // 绕原点逆时针旋转 A(弧度) 74 double tx=p.x,ty=p.y; 75 return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A)); 76 } 77 //向量的旋转 //底边线段ab 绕a逆时针旋转角度A,b->b1,sinl是sinA的值。 78 point rotate_point(double cosl,double sinl,point a, point b){ 79 b.x -= a.x; b.y -= a.y; 80 point c; 81 c.x = b.x * cosl - b.y * sinl + a.x; 82 c.y = b.x * sinl + b.y * cosl + a.y; 83 return c; 84 } 85 double xml(point x,point t1,point t2){ // 如果值为正,(t1-x)在(t2-x)的瞬时间方向 86 return det((t1-x),(t2-x)); 87 } 88 double area(point x,point y,point z){ 89 return (det(y-x,z-x)); 90 } 91 struct line { 92 point a,b; 93 line(){} 94 line(point x,point y):a(x),b(y){} 95 }; 96 point P_chuizhi_line(point a,point l1,point l2) // 求一个点,使得ac垂直于l1l2 97 { 98 point c; 99 l2.x -= l1.x; l2.y -= l1.y; 100 c.x = a.x - l1.x - l2.y + l1.x; 101 c.y = a.y - l1.y + l2.x + l1.y; 102 return c; 103 } 104 point P_To_seg(point P,line L) //点到线段 最近的一个点 105 { 106 point result; 107 double t = ((P-L.a)*(L.b-L.a))/((L.b-L.a)*(L.b-L.a)); 108 if(t >= 0 && t <= 1) 109 { 110 result.x = L.a.x + (L.b.x - L.a.x)*t; 111 result.y = L.a.y + (L.b.y - L.a.y)*t; 112 } 113 else 114 { 115 if(dist(P,L.a) < dist(P,L.b)) 116 result = L.a; 117 else result = L.b; 118 } 119 return result; 120 } 121 double dis_p_to_line(point p,line l){ //点到直线的距离 122 return fabs(area(p,l.a,l.b))/dist(l.a,l.b); 123 } 124 double dis_p_to_seg(point p,line l) //点到线段的距离 125 { 126 return dist(p,P_To_seg(p,l)); 127 } 128 double dis_pall_seg(point p1, point p2, point p3, point p4) //平行线段之间的最短距离 129 { 130 return min(min(dis_p_to_seg(p1,line(p3,p4)), 131 dis_p_to_seg(p2, line(p3, p4))), 132 min(dis_p_to_seg(p3,line(p1, p2)), 133 dis_p_to_seg(p4,line(p1, p2))) 134 ); 135 } 136 bool intbr(line l1,line l2) { // 线段相交 137 return 138 max(l1.a.x,l1.b.x) >= min(l2.a.x,l2.b.x) && 139 max(l2.a.x,l2.b.x) >= min(l1.a.x,l1.b.x) && 140 max(l1.a.y,l1.b.y) >= min(l2.a.y,l2.b.y) && 141 max(l2.a.y,l2.b.y) >= min(l1.a.y,l1.b.y) && 142 cmp((l2.a-l1.a)^(l1.b-l1.a))*cmp((l2.b-l1.a)^(l1.b-l1.a)) <= 0 && 143 cmp((l1.a-l2.a)^(l2.b-l2.a))*cmp((l1.b-l2.a)^(l2.b-l2.a)) <= 0; 144 } 145 point line_inter(point A,point B,point C,point D){ //直线相交交点 146 point ans; 147 double a1=A.y-B.y; 148 double b1=B.x-A.x; 149 double c1=A.x*B.y-B.x*A.y; 150 151 double a2=C.y-D.y; 152 double b2=D.x-C.x; 153 double c2=C.x*D.y-D.x*C.y; 154 155 ans.x=(b1*c2-b2*c1)/(a1*b2-a2*b1); 156 ans.y=(a2*c1-a1*c2)/(a1*b2-a2*b1); 157 return ans; 158 } 159 160 int n; 161 point ttmp; 162 point pt1[1001000],pt2[1001000]; 163 bool cmpx(point xx,point yy){ 164 if(cmp(xx.y-yy.y)==0) return xx.x<yy.x; 165 return xx.y<yy.y; 166 } 167 bool cmpd(point xx, point yy){ 168 double db=(xx-ttmp)^(yy-ttmp); 169 if(cmp(db)==0) return dist(xx,ttmp)<dist(yy,ttmp); 170 if(cmp(db)>0) return 1; 171 else return 0; 172 } 173 point grp1[1001000],grp2[1001000]; 174 int Graham(point* grp,point *pt,int n){ //凸包 175 int top=1; 176 sort(pt,pt+n,cmpx);ttmp=pt[0]; 177 sort(pt+1,pt+n,cmpd); 178 grp[0]=pt[0]; 179 grp[1]=pt[1]; 180 for(int i=2;i<n;i++){ 181 while(top>0){ 182 double db=(pt[i]-grp[top])^(grp[top]-grp[top-1]); 183 if(cmp(db)>=0) top--; 184 else break; 185 } 186 grp[++top]=pt[i]; 187 } 188 return top+1; 189 } 190 double rotating_calipers(point* grp ,int len){ //旋转卡壳求凸包直径 191 int i=0,j=1; 192 double ans=0; 193 while(i<len){ 194 while(area(grp[i],grp[i+1],grp[(j+1)%len])> 195 area(grp[i],grp[i+1],grp[j])) j=(j+1)%len; 196 ans=max(ans,max(dist(grp[i],grp[j]),dist(grp[i+1],grp[j]))); 197 i++; 198 } 199 return ans; 200 } 201 double rotating_calipers2(point* grp1,int len1,point* grp2,int len2){ //旋转卡壳 求两个凸包的最远距离 202 int p=0,q=0; 203 for(int i=0;i<len1;i++) if(grp1[i].y<grp1[p].y) p=i; 204 for(int i=0;i<len2;i++) if(grp2[i].y>grp2[q].y) q=i; 205 double ans=1e99,tmp; 206 grp1[len1]=grp1[0];//避免取模 207 grp2[len2]=grp2[0];//避免取模 208 for(int i=0;i<len1;i++){ 209 while(tmp=cmp(area(grp1[p],grp1[p+1],grp2[q+1])- 210 area(grp1[p],grp1[p+1],grp2[q]))>0) q=(q+1)%len2; 211 if(tmp==0) ans=min(ans,dis_pall_seg(grp1[p],grp1[p+1],grp2[q],grp2[q+1])); 212 else ans=min(ans,dis_p_to_seg(grp2[q],line(grp1[p],grp1[p+1]))); 213 p=(p+1)%len1; 214 } 215 216 return ans; 217 } 218 double rotating_calipers3(point* grp ,int len){ //旋转卡壳求凸包宽度 219 int p=0,q=0; 220 int tmp; 221 for(int i=0;i<len;i++) if(grp[i].y<grp[p].y) p=i; 222 for(int j=0;j<len;j++) if(grp[j].y>grp[q].y) q=j; 223 double ans=1e30; 224 for(int i=0;i<len;i++){ 225 while(tmp=cmp(area(grp[p],grp[p+1],grp[(q+1)%len])- 226 area(grp[p],grp[p+1],grp[q]))>0) q=(q+1)%len; 227 ans=min(ans,dis_p_to_line(grp[q],line(grp[p],grp[(p+1)%len]))); 228 p=(p+1)%len; 229 } 230 return ans; 231 } 232 double rotating_calipers4(point* grp,int len){ 233 double ans; 234 int xmin=0,xmax=0,ymin=0,ymax=0; 235 for(int i=0;i<len;i++) if(cmp(grp[xmin].x-grp[i].x)>0) xmin=i; 236 for(int i=0;i<len;i++) if(cmp(grp[xmax].x-grp[i].x)<0) xmax=i; 237 for(int i=0;i<len;i++) if(cmp(grp[ymin].y-grp[i].y)>0) ymin=i; 238 for(int i=0;i<len;i++) if(cmp(grp[ymax].y-grp[i].y)<0) ymax=i; 239 ans=(grp[ymax].y-grp[ymin].y)*(grp[xmax].x-grp[xmin].x); 240 grp[len]=grp[0]; 241 for(int i=0;i<len;i++){ 242 while(cmp(area(grp[ymin],grp[ymin+1],grp[ymax+1])- 243 area(grp[ymin],grp[ymin+1],grp[ymax]))>=0) ymax=(ymax+1)%len; 244 while(cmp(dot(grp[xmax+1],grp[ymin],grp[ymin+1])- 245 dot(grp[xmax],grp[ymin],grp[ymin+1]))>=0) xmax=(xmax+1)%len; 246 if(i==0) xmin=xmax; 247 while(cmp(dot(grp[xmin+1],grp[ymin+1],grp[ymin])- 248 dot(grp[xmin],grp[ymin+1],grp[ymin]))>=0) xmin=(xmin+1)%len; 249 double L1=dis_p_to_line(grp[ymax],line(grp[ymin],grp[ymin+1])); 250 point a=P_chuizhi_line(grp[xmin],grp[ymin],grp[ymin+1]); 251 double L2=dis_p_to_line(grp[xmax],line(grp[xmin],a)); 252 if(ans>L1*L2){ 253 ans=L1*L2; 254 255 } 256 ymin=(ymin+1)%len; 257 } 258 return ans; 259 } 260 struct node{ 261 double angle; 262 }fuck[1000]; 263 bool nodecmp(node a,node b){ 264 return a.angle<b.angle; 265 } 266 int main(){ 267 #ifndef ONLINE_JUDGE 268 freopen("input.txt","r",stdin); 269 #endif // ONLINE_JUDGE 270 int t;cin>>t; 271 while(t--){ 272 scanf("%d",&n); 273 for(int i=0;i<n;i++) pt1[i].input(); 274 long long ans=1ll*n*(n-1)*(n-2)*(n-3)/24; 275 for(int i=0;i<n;i++){ 276 int cnt=0; 277 for(int j=0;j<n;j++) if(i!=j){ 278 fuck[cnt++].angle=(pt1[j]-pt1[i]).angle()+pi; 279 } 280 sort(fuck,fuck+cnt,nodecmp); 281 for(int j=cnt;j<2*cnt;j++) fuck[j].angle=fuck[j-cnt].angle+2*pi; 282 int st=1; 283 long long tmp=0; 284 for(int j=0;j<cnt;j++){ 285 while(fuck[st].angle-fuck[j].angle<pi) st++; 286 if(st-j-1<2) continue; 287 tmp+=(st-j-1)*(st-j-2)/2; 288 } 289 ans-=(1ll*(n-1)*(n-2)*(n-3)/6-tmp); 290 } 291 printf("%lld\n",ans); 292 } 293 }
时间: 2024-11-20 06:47:38