凸包笔记
在平面直角坐标系上给你一堆点,让你从中选出一些点组成一个点集,使得它们恰好能构成一个凸多边形且全部点都在这个凸多边形内(含边界),那么选出来的这个点集就叫做这些点的凸包。
Graham算法
叉积,极角排序啥的大家肯定都会,我就不多说了,这篇博客还是以存代码为主。
具体思路就是先把所有点中最左下角的点拿出来(因为它必定在凸包上),然后其它点以它为原点极角排序,然后用一个栈维护凸包,数学证明和具体实现都很简单,我就不写了qwq
由于每个点最多出入栈一次所以是线性的时间复杂度,但是要排序所以多了个$log$。。。
时间复杂度$O(nlogn)$
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 using namespace std;
9 struct node{
10 int x,y;
11 }a[100001],s[100001];
12 int n,k,top=1;
13 double cross(node p,node p1,node p2){
14 return (p1.x-p.x)*(p2.y-p.y)-(p1.y-p.y)*(p2.x-p.x);
15 }
16 double dis(node x,node y){
17 return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
18 }
19 bool cmp(node p1,node p2){
20 double t=cross(a[0],p1,p2);
21 if(t>0||(t==0&&dis(a[0],p1)<dis(a[0],p2)))return true;
22 return false;
23 }
24 void graham(){
25 s[0]=a[0];
26 s[1]=a[1];
27 for(int i=2;i<n;i++){
28 while(cross(s[top-1],s[top],a[i])<0&&top)top--;
29 s[++top]=a[i];
30 }
31 }
32 int main(){
33 scanf("%d",&n);
34 for(int i=0;i<n;i++){
35 scanf("%d%d",&a[i].x,&a[i].y);
36 if(i==0||a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x))k=i;
37 }
38 swap(a[0],a[k]);
39 sort(a+1,a+n,cmp);
40 graham();
41 for(int i=0;i<=top;i++){
42 printf("%d %d\n",s[i].x,s[i].y);
43 }
44 return 0;
45 }
旋转卡壳
来,大家跟我念:xuan2zhuan3qia3ke2
就是拿两根直线“卡”着凸包,然后乱搞一下东西qwq
几道题目(待更完):
【BZOJ1185】【HNOI2007】最小矩形覆盖
旋转卡壳乱搞
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 struct node{
11 double x,y;
12 node(const double _x=0,const double _y=0){x=_x,y=_y;}
13 friend bool operator <(node x,node y){return fabs(x.y-y.y)<eps?x.x<y.x:x.y<y.y;}
14 friend bool operator ==(node x,node y){return fabs(x.x-y.x)<eps&&fabs(x.y-y.y)<eps;}
15 friend bool operator !=(node x,node y){return !(x==y);}
16 friend node operator +(node x,node y){return node(x.x+y.x,x.y+y.y);}
17 friend node operator -(node x,node y){return node(x.x-y.x,x.y-y.y);}
18 friend node operator *(node x,double y){return node(x.x*y,x.y*y);}
19 friend double operator *(node x,node y){return x.x*y.y-x.y*y.x;}
20 friend double operator /(node x,node y){return x.x*y.x+x.y*y.y;}
21 friend double dis(node x,node y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
22 friend double cross(node p,node p1,node p2){return (p1-p)*(p2-p);}
23 }a[100001],s[100001],ans[4];
24 int n,k,l,r,now,top=1;
25 double L,R,S,H,sq,anss=100000000000;
26 bool cmp(node p1,node p2){
27 double t=(p1-a[1])*(p2-a[1]);
28 if(t>0||(fabs(t)<eps&&dis(a[1],p1)<dis(a[1],p2)))return true;
29 return false;
30 }
31
32 int main(){
33 scanf("%d",&n);
34 for(int i=1;i<=n;i++){
35 scanf("%lf%lf",&a[i].x,&a[i].y);
36 if(i==1||a[i]<a[k])k=i;
37 }
38 swap(a[1],a[k]);
39 sort(a+2,a+n+1,cmp);
40 s[1]=a[1];
41 for(int i=2;i<=n;i++){
42 while(top>1&&(s[top]-s[top-1])*(a[i]-s[top])<eps)top--;
43 s[++top]=a[i];
44 }
45 s[0]=s[top];
46 l=r=now=1;
47 for(int i=0;i<top;i++){
48 S=dis(s[i],s[i+1]);
49 while((s[i+1]-s[i])*(s[now+1]-s[i])-(s[i+1]-s[i])*(s[now]-s[i])>-eps)now=(now+1)%top;
50 while((s[i+1]-s[i])/(s[r+1]-s[i])-(s[i+1]-s[i])/(s[r]-s[i])>-eps)r=(r+1)%top;
51 if(!i)l=r;
52 while((s[i+1]-s[i])/(s[l+1]-s[i])-(s[i+1]-s[i])/(s[l]-s[i])<eps)l=(l+1)%top;
53 L=((s[i+1]-s[i])/(s[l]-s[i]))/S;
54 R=((s[i+1]-s[i])/(s[r]-s[i]))/S;
55 H=((s[i+1]-s[i])*(s[now]-s[i]))/S;
56 if(H<0)H=-H;
57 sq=(R-L)*H;
58 if(sq<anss){
59 anss=sq;
60 ans[0]=s[i]+(s[i+1]-s[i])*(R/S);
61 ans[1]=ans[0]+(s[r]-ans[0])*(H/dis(ans[0],s[r]));
62 ans[2]=ans[1]-(ans[0]-s[i])*((R-L)/dis(ans[0],s[i]));
63 ans[3]=ans[2]+ans[0]-ans[1];
64 }
65 }
66 printf("%.5lf\n",anss);
67 k=0;
68 for(int i=1;i<=3;i++)if(ans[i]<ans[k])k=i;
69 for(int i=0;i<=3;i++)printf("%.5lf %.5lf\n",ans[(k+i)%4].x,ans[(k+i)%4].y);
70 return 0;
71 }