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 } 

 

posted @ 2017-01-19 23:15  mzl0707  阅读(185)  评论(0编辑  收藏  举报