1. 程式人生 > >POJ1113 Wall【凸包】

POJ1113 Wall【凸包】

ons 逆時針 print () 圍墻 自己 排序 三角形 根據

題意:

求把城堡圍起來需要的最小墻壁周長。

思路:

圍墻周長為=n條平行於凸包的線段+n條圓弧的長度=凸包周長+圍墻離城堡距離L為半徑的圓周長。

代碼:

。。。還是看大佬寫的,自己做個記錄方便日後復習。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N=2e5+20;
const double PI=acos(-1.0);
struct
point{ int x,y; }p[N]; int n; int stack[N],top; int cross(point p0,point p1,point p2)//p0p1 * p0p2叉積 判斷順/逆時針 { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(point p1,point p2) { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(point p1,point p2)//
極角排序 p[0]為最下方&&最左邊的點 { int tmp=cross(p[0],p1,p2); if(tmp>0) return true; else if(tmp==0&&dis(p[0],p1)<dis(p[0],p2)) return true;//角度相同,距離小在前 else return false; } void Graham(int n)//求凸包 { if(n==1){top=0;stack[0]=0;} if(n==2) { top=1; stack[0]=0; stack[
1]=1; } if(n>2) { for(int i=0;i<=1;i++) stack[i]=i; top=1; for(int i=2;i<n;i++)//O(2n) 求出前i個點集形成的凸包 { //可以根據歸納法來證明,棧頂~0為前i-1個點集的凸包的頂點 //因為按極角排序後,若叉積<=0 則棧頂在(p[0],p[i],次棧頂)構成的三角形內部,棧頂不為前i個點集形成的凸包的極點. while(top>0&&cross(p[stack[top-1]],p[stack[top]],p[i])<=0) top--; top++; stack[top]=i; } } } int main() { double L; while(cin>>n>>L) { int low=0; for(int i=0;i<n;i++) { cin>>p[i].x>>p[i].y; if((p[low].y==p[i].y&&p[low].x>p[i].x)||p[low].y>p[i].y) low=i; } swap(p[0],p[low]);//p[0]為最下方&&最左邊的點 sort(p+1,p+n,cmp); Graham(n); double res=0; for(int i=0;i<top;i++) res+=dis(p[stack[i]],p[stack[i+1]]); res+=dis(p[stack[0]],p[stack[top]]); res+=2*PI*L; printf("%d\n",int(res+0.5));//四設五入 } return 0; }

POJ1113 Wall【凸包】