알고리즘/알고리즘 노트

[코드모음]-기하,

산을좋아한라쯔 2016. 8. 19. 16:39
반응형

/* 기하 Basic structure */

struct Point{

        double x, y;

 

        Point(){}

        Point(double _x, double _y){ x = _x; y = _y; }

 

        Point operator + (const Point& rhs) const{ return Point(x+rhs.x, y+rhs.y); }

        Point operator - (const Point& rhs) const{ return Point(x - rhs.x, y - rhs.y); }

        bool operator < (const Point& rhs){   return (x != rhs.x) ? (x < rhs.x) : (y < rhs.y); }

        Point operator * (double a) { return Point(a * x, a * y); }

 

        double len(){ return sqrt((double)x*x + y*y); }

        Point normalize(){

               double len = sqrt((double)x*x + y*y);

               return Point(x/len, y/len);

        }

        Point projection(Point& b){

               Point n = b.normalize();

               return n * dot(n,*this);

        }

};

double dot(Point& a, Point& b){ return a.x * b.x + a.y * b.y; }

double cross(Point &a, Point& b){ return a.x * b.y - a.y * b.x; }

 

/* 라인 교차여부 */

nt cross(P a, P b) {      return a.x * b.y - a.y*b.x; }

int ccw(P a, P b, P c) {return cross(b - a, c - a);} 

bool isInter(P a, P b, P c, P d) {

         int ab = ccw(a, b, c) * ccw(a, b, d);

         int cd = ccw(c, d, a) * ccw(c, d, b);

         if (ab == 0 && cd == 0) {

                  if (b < a) swap(a, b);

                  if (d < c) swap(c, d);

                  // [a..b] 경우만 true. , !( d<- a~b -> c )

                  return !(d<a || b<c);

         }

         return ab <= 0 && cd <= 0;

}

 

/* 내외부 판별 */

bool isInside(P q, vector<P>& p) {

         int cnt = 0;

         int x, x1, x2, y, y1, y2;

 

         x = q.x; y = q.y;

         for (int i = 0; i < p.size(); ++i) {

                  int j = (i + 1) % p.size();

                  x1 = p[i].x; y1 = p[i].y;

                  x2 = p[j].x; y2 = p[j].y;

                 

                  //핵심. [low..high) . 낮은쪽 점과  위쪽 라인을 지날 때만. 평행의 경우는 해당 안됨

                  if ((y1 > y) != (y2 > y)) {

                           // 점을 이루는 직선상에서, y점에 대한 x

                           double atX = (x2 - x1) * (y - y1) / (y2 - y1) + x1;

                           if (x < atX) ++cnt;

                  }

         }

         return (cnt % 2) > 0; //홀수이면 inside

}

 

/* convex hull */

ll ccw(Point p1, Point p2, Point p3) {

        return (p2 - p1).cross(p3 - p1);

}

 

double dist(Point a, Point b) {

        return (b.x - a.x) * (b.x - a.x) + (b.y - a.y)*(b.y - a.y);

}

 

bool comp(Point a, Point b) {

        ll cr = ccw(mini, a, b);

        if (cr > 0 || (cr == 0 && dist(mini, a) < dist(mini, b))) return true;

        return false;

}

 

int graham(){

        //1. find most below y. if same y, choose min x -> O(n)

        mini = a[1];

        for (int i = 2; i <= n; i++) {

               if (mini.y > a[i].y || mini.y == a[i].y && mini.x > a[i].x) mini = a[i];

        }

 

        //2. sort       

        sort(a + 1, a + n + 1, comp);

 

        //3. a[n]->a[0]에서부터 시작해서,

        int st_top = 0;

        st[0] = a[n]; //주의!!!

        st[++st_top] = a[1];

 

        for (int i = 2; i <= n; ++i) { //n-1이 아닌 n까지라는 것에 유의

               while (ccw(st[st_top - 1], st[st_top], a[i]) <= 0) st_top--; //주의!!

               st[++st_top] = a[i];

        }

 

        return st_top;

}

 

/* 회전하는 캘리퍼스 - 컨벡스헐의 가장 긴 거리 구하기*/

- 볼록다각형에 버니아캘리퍼스를 대고, 돌려가면서 가장 거리가 긴 두 점을 찾는 원리 이용

1. x축을 기준으로, 다각형의 가장 왼쪽에 있는 점과, 가장 오른쪽에 있는 점을 찾는다. 그 점의 인덱스: left, right

2. 다각형의 각 선분에 대한 단위벡터를 구해 둔다. 

        vector<V> u(N+1);

        for (int i = 1; i <= N; ++i) u[i] = (p[(i + 1) % N] - p[i]).normalize();

3. a=left에서 b=right까지 단위벡터 선분과 캘리퍼스와의 각을 구하면서 작은 각도쪽으로 회전.

   즉, cosA= dot(diaA, u[a])와 cosB를 통해 A와 B의 각도를 비교하고, 작은쪽 선분으로 dia 치환

4. 위의 루틴을 돌면서, p[a]~p[b] 사잇거리가 가장 긴 것 찾아낸다.


double diameter() {

         //1. 가장 왼쪽, 오른쪽 찾는다. idx:left, right

         int leftMax = p[1].x, rightMax = p[1].x;

         int left = 1, right = 1;

         for (int i = 2; i <= N; ++i) {

                  if (p[i].x < leftMax) {

                           leftMax = p[i].x; left = i;

                  }

                  if (p[i].x > rightMax) {

                           rightMax = p[i].x; right = i;

                  }

         }

 

         //2. 도형의 선분을 단위벡터로 구해둔다. u[i]: i ~ (i+1) 사이 단위벡터

         vector<V> u(N+1);

         for (int i = 1; i <= N; ++i)        u[i] = (p[(i + 1) % N] - p[i]).normalize();

        

 

         //3. a=left에서 b=right까지 단위벡터 선분과 calipers와의 각을 구하면서 작은 각도쪽으로 회전.

         //   , cosA= dot(diaA, u[a]) cosB 통해 A B 각도를 비교하고, 작은쪽 선분으로 dia 치환

         double maxLen = (p[right] - p[left]).length();

         V diaA = V(0, 1);

         V diaB = V(0, -1);

         int a = left, b = right;

         while (a!=right || b!=left) {

                  double cosA = dot(diaA, u[a]);

                  double cosB = dot(diaB, u[b]);

 

                  if (cosA > cosB) { // ==> A < B

                           diaA = u[a];

                           diaB = V(diaA.x * -1, -diaA.y * -1);

                           a = (a + 1) % N;

                  }

                  else {

                           diaB = u[b];

                           diaA = V(diaB.x * -1, diaB.y * -1);

                           b = (b + 1) % N;

                  }

                  double len = (p[b] - p[a]).length();

                  if (len > maxLen) maxLen = len;

         }

 

         return maxLen;

}

 


-끝-

반응형

'알고리즘 > 알고리즘 노트' 카테고리의 다른 글

[코드모음]-정렬, 자료구조  (0) 2016.08.19
[코드모음]-DP  (0) 2016.08.19
[코드 모음]-탐색, 그래프  (0) 2016.08.16
[수학]-문제  (0) 2016.08.11
[그래프]-조건 추가된 문제들  (0) 2016.08.07