洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows || 凸包模板
整篇都是仅做记录...
蓝书上的板子。水平序,单调栈。先求下凸包,再求上凸包。叉积的作用是判定向量的位置关系。
48行的作用是在求上凸包的时候不至于去删下凸包中的点。上凸包中第一个点被认为是t1。
另:如果不希望在凸包边上有输入点(指多点共线且在凸包上时都当做在凸包上的,而不是像这个一样仅保留第一个和最后一个),将>=改成>
另:蓝书上原文是把叉积的两个参数互换,然后<=0。实际没有区别。
另:如果需要去掉得到凸包的最后多余一个点(与第一个是一样的),那么要加一句:
if(n>1) m--;
另:蓝书上那张图(示意)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 const double eps=1e-7; 6 struct Point 7 { 8 double x,y; 9 Point(double x1=0,double y1=0):x(x1),y(y1){} 10 friend bool operator<(const Point& a,const Point& b) 11 { 12 return a.x<b.x||(a.x==b.x&&a.y<b.y); 13 } 14 }p[10100],ans[10100]; 15 int top; 16 double anss; 17 int dcmp(double a) 18 { 19 if(fabs(a)<eps) return 0; 20 return a>0?a:-a; 21 } 22 double cross(const Point& a,const Point& b) 23 { 24 return a.x*b.y-b.x*a.y; 25 } 26 Point operator-(const Point& a,const Point& b) 27 { 28 return Point(a.x-b.x,a.y-b.y); 29 } 30 double len(const Point& x) 31 { 32 return sqrt(x.x*x.x+x.y*x.y); 33 } 34 int n; 35 int main() 36 { 37 int i; 38 scanf("%d",&n); 39 for(i=1;i<=n;i++) 40 scanf("%lf%lf",&p[i].x,&p[i].y); 41 sort(p+1,p+n+1); 42 for(i=1;i<=n;i++) 43 { 44 //while(top>1&&cross(p[i]-ans[top-2],ans[top-1]-ans[top-2])>0) --top; 45 while(top>1&&cross(p[i]-ans[top-2],ans[top-1]-ans[top-2])>=0) --top; 46 ans[top++]=p[i]; 47 } 48 int t1=top; 49 for(i=n-1;i>=1;i--) 50 { 51 while(top>t1&&cross(p[i]-ans[top-2],ans[top-1]-ans[top-2])>=0) --top; 52 ans[top++]=p[i]; 53 } 54 for(i=1;i<top;i++) 55 anss+=len(ans[i]-ans[i-1]); 56 printf("%.2lf",anss); 57 return 0; 58 }