在二维空间中,凸包可以简单的认为是最小的包含所有点的凸多边形。
简单的卷包裹法:寻找最边缘(最下方的,次之是最左边的;或者最左边的,次之最下边)点。假想用一根绳子向右逆时针旋转碰到另一个点,这样新找到的点作为端点,继续旋转绳子重复找点的步骤,一直围成一个凸多边形。时间复杂度:O(n^2) //我把此代码和Graham-scan比较了一下,没有理解为什么他就是 O(n^2) T_T
(如果在寻找的射线上有多个点的情况,使用和保留离前端点最远的那一点)
因为涉及到旋转和夹角,所以运用到了叉积。
例子:
hdu 1348 wall
http://acm.hdu.edu.cn/showproblem.php?pid=1348
大致题意:给出N个点,它所形成的多边形向外撑长L,新的多边形的周长是多少?
分析:每对对顶角的和是180度,n多边形有n个顶点,同时多边形的内角和是180(n-2),那么外围的夹角和就应该是180n-180(n-2)=360
于是得到结论:多边形的周长+圆的周长就是所求。
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
struct point{
int x,y;
}pt[1005];
int sta[1005],ans[1005],cnt;
int cmp(point a,point b){
//左下角优先 先左再下
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int cross(point p0,point p1,point p2){ //大于0, 逆时针
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
void convex(int n){
sort(pt,pt+n,cmp);
cnt=0;
int top=0;
sta[top++]=0; sta[top++]=1; //下凸包
for(int i=2;i<n;i++){
while(top>1&&cross(pt[sta[top-2]],pt[sta[top-1]],pt[i])<=0) {
top--;
}
sta[top++]=i;
}
for(int i=0;i<top;i++) ans[cnt++]=sta[i];
top=0;
sta[top++]=n-1; sta[top++]=n-2; //求上凸包 (将pt[n-1]和pt[0]连接起来。)
for(int i=n-3;i>=0;i--){
while(top>1&&cross(pt[sta[top-2]],pt[sta[top-1]],pt[i])<=0){
top--;
}
sta[top++]=i;
}
for(int i=0;i<top;i++) ans[cnt++]=sta[i];
}
int main()
{
//freopen("cin.txt","r",stdin);
int n,l,t;
double Pi=acos(0.0)*2;
cin>>t;
while(t--){
scanf("%d%d",&n,&l);
for(int i=0;i<n;i++){
scanf("%d%d",&pt[i].x,&pt[i].y);
}
convex(n);
double res=2*Pi*l;
for(int i=0;i<cnt-1;i++){
res+=sqrt(1.0*(pt[ans[i]].x-pt[ans[i+1]].x)*(pt[ans[i]].x-pt[ans[i+1]].x)
+(pt[ans[i]].y-pt[ans[i+1]].y)*(pt[ans[i]].y-pt[ans[i+1]].y));
}
printf("%.0lf\n",res);
if(t) puts("");
}
return 0;
}
再来模仿一种写法:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
struct point{
int x,y;
}pt[1005],ans[1005];
int cnt;
int cmp(point a,point b){
if(a.x==b.x) return a.y<b.y; //左下角优先 先左再下
return a.x<b.x;
}
int cross(point p0,point p1,point p2){ //大于0, 逆时针
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double length(point a,point b){
return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void convex(int n){
sort(pt,pt+n,cmp);
cnt=0;
for(int i=0;i<n;i++){ //下凸包
while(cnt>1&&cross(ans[cnt-2],ans[cnt-1],pt[i])<=0) {
cnt--;
}
ans[cnt++]=pt[i];
}
int key=cnt;
//求上凸包 (将pt[n-1]和pt[0]连接起来。)
for(int i=n-2;i>=0;i--){
while(cnt>key&&cross(ans[cnt-2],ans[cnt-1],pt[i])<=0){
cnt--;
}
ans[cnt++]=pt[i];
}
}
int main()
{
//freopen("cin.txt","r",stdin);
int n,l;
double Pi=atan(1.0)*4;
int t=0;
cin>>t;
while(t--){
scanf("%d%d",&n,&l);
for(int i=0;i<n;i++){
scanf("%d%d",&pt[i].x,&pt[i].y);
}
convex(n);
double res=2*Pi*l;
for(int i=0;i<cnt-1;i++){
res+=length(ans[i],ans[i+1]);
}
printf("%.0lf\n",res);
if(t) puts("");
}
return 0;
}