Pentium.Labs

System全家桶:https://zhuanlan.zhihu.com/c_1238468913098731520

导航

poj1113 凸包

result=对所有点凸包周长+pi*2*L

WA了一次,被Pi的精度坑了

以后注意Pi尽可能搞精确一点。Pi=3.14还是不够用

 

Code:

  1 #include<vector>
  2 #include<list>
  3 #include<map>
  4 #include<set>
  5 #include<deque>
  6 #include<queue>
  7 #include<stack>
  8 #include<bitset>
  9 #include<algorithm>
 10 #include<functional>
 11 #include<numeric>
 12 #include<utility>
 13 #include<iostream>
 14 #include<sstream>
 15 #include<iomanip>
 16 #include<cstdio>
 17 #include<cmath>
 18 #include<cstdlib>
 19 #include<cctype>
 20 #include<string>
 21 #include<cstring>
 22 #include<cstdio>
 23 #include<cmath>
 24 #include<cstdlib>
 25 #include<ctime>
 26 #include<climits>
 27 #include<complex>
 28 #define mp make_pair
 29 #define pb push_back
 30 using namespace std;
 31 const double eps=1e-8;//精度
 32 const double pi=acos(-1.0);//π
 33 const double inf=1e20;//无穷大
 34 const int maxp=1111;//最大点数
 35 
 36 /*
 37     判断d是否在精度内等于0
 38 */
 39 int dblcmp(double d)
 40 {
 41     if (fabs(d)<eps)return 0;
 42     return d>eps?1:-1;
 43 }
 44 /*
 45     求x的平方
 46 */
 47 inline double sqr(double x){return x*x;}
 48 /*
 49     点/向量
 50 */
 51 struct point
 52 {
 53     double x,y;
 54     point(){}
 55     point(double _x,double _y):x(_x),y(_y){};
 56     //读入一个点
 57     void input()
 58     {
 59         scanf("%lf%lf",&x,&y);
 60     }
 61     //输出一个点
 62     void output()
 63     {
 64         printf("%.2f %.2f\n",x,y);
 65     }
 66     //判断两点是否相等
 67     bool operator==(point a)const
 68     {
 69         return dblcmp(a.x-x)==0&&dblcmp(a.y-y)==0;
 70     }
 71     //判断两点大小
 72     bool operator<(point a)const
 73     {
 74         return dblcmp(a.x-x)==0?dblcmp(y-a.y)<0:x<a.x;
 75     }
 76     //点到源点的距离/向量的长度
 77     double len()
 78     {
 79         return hypot(x,y);
 80     }
 81     //点到源点距离的平方
 82     double len2()
 83     {
 84         return x*x+y*y;
 85     }
 86     //两点间的距离
 87     double distance(point p)
 88     {
 89         return hypot(x-p.x,y-p.y);
 90     }
 91     //向量加
 92     point add(point p)
 93     {
 94         return point(x+p.x,y+p.y);
 95     }
 96     //向量减
 97     point sub(point p)
 98     {
 99         return point(x-p.x,y-p.y);
100     }
101     //向量乘
102     point mul(double b)
103     {
104         return point(x*b,y*b);
105     }
106     //向量除
107     point div(double b)
108     {
109         return point(x/b,y/b);
110     }
111     //点乘
112     double dot(point p)
113     {
114         return x*p.x+y*p.y;
115     }
116     //叉乘
117     double det(point p)
118     {
119         return x*p.y-y*p.x;
120     }
121     //XXXXXXX
122     double rad(point a,point b)
123     {
124         point p=*this;
125         return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p))));
126     }
127     //截取长度r
128     point trunc(double r)
129     {
130         double l=len();
131         if (!dblcmp(l))return *this;
132         r/=l;
133         return point(x*r,y*r);
134     }
135     //左转90度
136     point rotleft()
137     {
138         return point(-y,x);
139     }
140     //右转90度
141     point rotright()
142     {
143         return point(y,-x);
144     }
145     //绕点p逆时针旋转angle角度
146     point rotate(point p,double angle)
147     {
148         point v=this->sub(p);
149         double c=cos(angle),s=sin(angle);
150         return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
151     }
152 };
153 /*
154     线段/直线
155 */
156 struct line
157 {
158     point a,b;
159     line(){}
160     line(point _a,point _b)
161     {
162         a=_a;
163         b=_b;
164     }
165     //判断线段相等
166     bool operator==(line v)
167     {
168         return (a==v.a)&&(b==v.b);
169     }
170     //点p做倾斜角为angle的射线
171     line(point p,double angle)
172     {
173         a=p;
174         if (dblcmp(angle-pi/2)==0)
175         {
176             b=a.add(point(0,1));
177         }
178         else
179         {
180             b=a.add(point(1,tan(angle)));
181         }
182     }
183     //直线一般式ax+by+c=0
184     line(double _a,double _b,double _c)
185     {
186         if (dblcmp(_a)==0)
187         {
188             a=point(0,-_c/_b);
189             b=point(1,-_c/_b);
190         }
191         else if (dblcmp(_b)==0)
192         {
193             a=point(-_c/_a,0);
194             b=point(-_c/_a,1);
195         }
196         else
197         {
198             a=point(0,-_c/_b);
199             b=point(1,(-_c-_a)/_b);
200         }
201     }
202     //读入一个线段
203     void input()
204     {
205         a.input();
206         b.input();
207     }
208     //校准线段两点
209     void adjust()
210     {
211         if (b<a)swap(a,b);
212     }
213     //线段长度
214     double length()
215     {
216         return a.distance(b);
217     }
218     //直线倾斜角 0<=angle<180
219     double angle()
220     {
221         double k=atan2(b.y-a.y,b.x-a.x);
222         if (dblcmp(k)<0)k+=pi;
223         if (dblcmp(k-pi)==0)k-=pi;
224         return k;
225     }
226     //点和线段关系
227     //1 在逆时针
228     //2 在顺时针
229     //3 平行
230     int relation(point p)
231     {
232         int c=dblcmp(p.sub(a).det(b.sub(a)));
233         if (c<0)return 1;
234         if (c>0)return 2;
235         return 3;
236     }
237     //点是否在线段上
238     bool pointonseg(point p)
239     {
240         return dblcmp(p.sub(a).det(b.sub(a)))==0&&dblcmp(p.sub(a).dot(p.sub(b)))<=0;
241     }
242     //两线是否平行
243     bool parallel(line v)
244     {
245         return dblcmp(b.sub(a).det(v.b.sub(v.a)))==0;
246     }
247     //线段和线段关系
248     //0 不相交
249     //1 非规范相交
250     //2 规范相交
251     int segcrossseg(line v)
252     {
253         int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
254         int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
255         int d3=dblcmp(v.b.sub(v.a).det(a.sub(v.a)));
256         int d4=dblcmp(v.b.sub(v.a).det(b.sub(v.a)));
257         if ((d1^d2)==-2&&(d3^d4)==-2)return 2;
258         return (d1==0&&dblcmp(v.a.sub(a).dot(v.a.sub(b)))<=0||
259                 d2==0&&dblcmp(v.b.sub(a).dot(v.b.sub(b)))<=0||
260                 d3==0&&dblcmp(a.sub(v.a).dot(a.sub(v.b)))<=0||
261                 d4==0&&dblcmp(b.sub(v.a).dot(b.sub(v.b)))<=0);
262     }
263     //线段和直线v关系
264     int linecrossseg(line v)//*this seg v line
265     {
266         int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
267         int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
268         if ((d1^d2)==-2)return 2;
269         return (d1==0||d2==0);
270     }
271     //直线和直线关系
272     //0 平行
273     //1 重合
274     //2 相交
275     int linecrossline(line v)
276     {
277         if ((*this).parallel(v))
278         {
279             return v.relation(a)==3;
280         }
281         return 2;
282     }
283     //求两线交点
284     point crosspoint(line v)
285     {
286         double a1=v.b.sub(v.a).det(a.sub(v.a));
287         double a2=v.b.sub(v.a).det(b.sub(v.a));
288         return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
289     }
290     //点p到直线的距离
291     double dispointtoline(point p)
292     {
293         return fabs(p.sub(a).det(b.sub(a)))/length();
294     }
295     //点p到线段的距离
296     double dispointtoseg(point p)
297     {
298         if (dblcmp(p.sub(b).dot(a.sub(b)))<0||dblcmp(p.sub(a).dot(b.sub(a)))<0)
299         {
300             return min(p.distance(a),p.distance(b));
301         }
302         return dispointtoline(p);
303     }
304     //XXXXXXXX
305     point lineprog(point p)
306     {
307         return a.add(b.sub(a).mul(b.sub(a).dot(p.sub(a))/b.sub(a).len2()));
308     }
309     //点p关于直线的对称点
310     point symmetrypoint(point p)
311     {
312         point q=lineprog(p);
313         return point(2*q.x-p.x,2*q.y-p.y);
314     }
315 };
316 
317 /*
318     多边形
319 */
320 struct polygon
321 {
322     int n;//点个数
323     point p[maxp];//顶点
324     //读入一个多边形
325     void input(int n)
326     {
327         for (int i=0;i<n;i++)
328         {
329             p[i].input();
330         }
331     }
332     struct cmp
333     {
334         point p;
335         cmp(const point &p0){p=p0;}
336         bool operator()(const point &aa,const point &bb)
337         {
338             point a=aa,b=bb;
339             int d=dblcmp(a.sub(p).det(b.sub(p)));
340             if (d==0)
341             {
342                 return dblcmp(a.distance(p)-b.distance(p))<0;
343             }
344             return d>0;
345         }
346     };
347     void norm()
348     {
349         point mi=p[0];
350         for (int i=1;i<n;i++)mi=min(mi,p[i]);
351         sort(p,p+n,cmp(mi));
352     }
353     //求凸包存入多边形convex
354     void getconvex(polygon &convex)
355     {
356         int i,j,k;
357         sort(p,p+n);
358         convex.n=n;
359         for (i=0;i<min(n,2);i++)
360         {
361             convex.p[i]=p[i];
362         }
363         if (n<=2)return;
364         int &top=convex.n;
365         top=1;
366         for (i=2;i<n;i++)
367         {
368             while (top&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
369                 top--;
370             convex.p[++top]=p[i];
371         }
372         int temp=top;
373         convex.p[++top]=p[n-2];
374         for (i=n-3;i>=0;i--)
375         {
376             while (top!=temp&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
377                 top--;
378             convex.p[++top]=p[i];
379         }
380     }
381     //取得周长
382     double getcircumference()
383     {
384         double sm=0;
385         int i;
386         for (i=0;i<n;i++)
387         {
388             sm+=p[i].distance(p[(i+1)%n]);
389             //printf("%.2f\n",sm);
390         }
391         return sm;
392     }
393 };
394 
395 struct polygon P,R;
396 int N,L;
397 double sum=0;
398 
399 int main()
400 {
401     //freopen("in2.txt","r",stdin);
402 
403     cin>>N>>L;
404     P.n=N;
405     P.input(N);
406     P.getconvex(R);
407 
408     sum=R.getcircumference();
409     //cout<<R.n<<endl;
410     //for (int i=0;i<R.n;i++)
411     //    printf("%.2f %.2f\n",R.p[i].x,R.p[i].y);
412 
413     sum+=3.14159265358979723846*(double)L*2;
414     printf("%.0f\n",sum);
415 
416     return 0;
417 }
View Code

 

最基础的凸包算法:卷包裹算法。基本思想就好像把所有的点比作一堆钉子,拿一根绳子捆在最左边的点上,然后按顺时针or逆时针围一圈

http://www.cnblogs.com/Booble/archive/2011/02/28/1967179.html

 

------------------------我是傲傲傲娇哒分割线---------------------------------

 

求凸包的Andrew算法:

设所有点在平面坐标系上,从最左下角的点开始,从左到右来一次,再从右到左来一次,最后回到起点。

把所有点按x和y坐标作为关键字从小到大排序(x优先)。先把第一个点和第二个点加入凸包。

在扫描的过程中,当前凸包的前进方向即倒数第二个入凸包的点->倒数第一个入凸包的点这一向量。

若新点在凸包前进方向的左边则继续,否则依次删除最近加入凸包的点,直到新点在左边为止。

 

eg:

STEP1:当前已经加入了这些点:

 

STEP2:加入了点4

 

STEP3:这时再想加5的时候发现5在向量3->4的右边,加不了了-_-||

     于是把4删掉。

 

STEP4:这时5在向量2->3的左边了。加5

    PS:如果删掉了还是在右边的话就接着删

 

 

 

判断新点在某个向量的左边还是右边可以用叉乘。

posted on 2015-01-20 17:48  Pentium.Labs  阅读(303)  评论(0编辑  收藏  举报



Pentium.Lab Since 1998