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 }
最基础的凸包算法:卷包裹算法。基本思想就好像把所有的点比作一堆钉子,拿一根绳子捆在最左边的点上,然后按顺时针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) 编辑 收藏 举报