关于数论【凸包】
凸包,算是计算几何的知识了,今天补了一发。
在一个平面坐标系上有n个点,用笔画一个多边形,使得多边形包含这n个点(点在多边形的边上也算包含)。求多边形的最小周长。
这就是要你求一个凸包的周长。
那我们如何得到一个凸包的所有顶点呢?可以发现,这个凸包肯定是用部分给出的顶点连接,包含其他全部的点。具体的做法,就是先找到一个最下最左的点,以他为基准点,按逆时针的方向,将其他的点排序,然后弄栈,保证新加入的点一定在逆时针方向(保证凹包不出现)否则踢栈顶,因为加入的新点和次栈顶所连线肯定包含栈顶。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct point { double x,y; }p[1100],sta[1100];int top; double gougu(point p1,point p2){return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));} double multi(point p1,point p2,point p0) { double x1,y1,x2,y2; x1=p1.x-p0.x; y1=p1.y-p0.y; x2=p2.x-p0.x; y2=p2.y-p0.y; return x1*y2-x2*y1; } bool cmp(point p1,point p2) { double t=multi(p1,p2,p[1]); if(t<0||(t==0&&gougu(p1,p[1])>gougu(p2,p[1])))return false; return true; } int n; void garham() { sort(p+2,p+n+1,cmp);//按逆时针放点 top=2;sta[1]=p[1];sta[2]=p[2]; for(int i=3;i<=n;i++) { while(top>1&&multi(sta[top],p[i],sta[top-1])<=0)top--; //判断一下以top-1为基准点,新来的点p[i]在栈顶的点哪边,如果在顺时针方向,那么说明p[i]可以包含到它,那就踢栈顶 sta[++top]=p[i]; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); if(p[1].y>p[i].y||(p[1].y==p[i].y&&p[1].x>p[i].x))//确定最下最左的点 { swap(p[1],p[i]); } } garham(); double ans=0.0; for(int i=1;i<top;i++)ans+=gougu(sta[i],sta[i+1]); ans+=gougu(sta[top],sta[1]); printf("%.4lf",ans); return 0; }
pain and happy in the cruel world.