bzoj1670: [Usaco2006 Oct]Building the Moat护城河的挖掘(凸包入门)
题目大意:找一圈点能把所有点包围起来,求这个圈的长度
算是模板吧,其实也不难,就是细节很多,代码很丑(凡是计算几何的题都很不怎么简洁)
大概思路是这样的
1、找y最小前提下x最小的一个点作为基点
2、按照其他点和基点的连线的斜率逆时针排序,排序过程不是以k来判断,而是以两两的叉积判断
向量a,b :a<b 当且仅当 a*b > 0
3、维护一个栈,逆时针计算凸包的向量,设栈顶为点x,栈顶下面那个点为y,当前点为p
如果(x-y)*(p-y)>0那么向量p入栈,否则x出栈
有趣
1 #include<stdio.h> 2 #include<string.h> 3 #include<cmath> 4 #include<algorithm> 5 #define sqr(x) ((x)*(x)) 6 #define eps 1e-6 7 using namespace std; 8 const int maxn = 10010; 9 struct vet{ 10 double x,y; 11 12 friend double operator*(vet a, vet b){ 13 return a.x*b.y-a.y*b.x; 14 } 15 16 friend vet operator-(vet a, vet b){ 17 return (vet){a.x-b.x, a.y-b.y}; 18 } 19 20 friend double dis(vet a, vet b){ 21 return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); 22 } 23 }e[maxn],st[maxn]; 24 int n,top=0; 25 double tx,ty; 26 27 bool operator<(vet a, vet b){ 28 double t=(a-e[1])*(b-e[1]); 29 if (fabs(t)<=eps) return (dis(a,e[1])<dis(b,e[1])); 30 return t>eps; 31 } 32 33 int main(){ 34 scanf("%d", &n); 35 tx=ty=20000000; int tmp=1; 36 for (int i=1; i<=n; i++){ 37 scanf("%lf%lf", &e[i].x, &e[i].y); 38 if (e[i].y<ty || (e[i].y==ty && e[i].x<tx)) 39 tmp=i,tx=e[i].x,ty=e[i].y; 40 } 41 swap(e[1],e[tmp]); 42 sort(e+2,e+1+n); 43 st[++top]=e[1]; st[++top]=e[2]; 44 for (int i=3; i<=n; i++){ 45 while (top>1 && (st[top]-st[top-1])*(e[i]-st[top-1])<=0) top--; 46 st[++top]=e[i]; 47 } 48 double ans=dis(st[top],st[1]); 49 for (int i=2; i<=top; i++) ans+=dis(st[i],st[i-1]); 50 printf("%.2lf\n", ans); 51 return 0; 52 }