본문 바로가기
PS/BOJ

[BOJ 1310] 달리기 코스

by Saerong2 2020. 8. 26.

문제 링크

https://www.acmicpc.net/problem/1310

 

1310번: 달리기 코스

첫째 줄에 기둥의 개수 N(1≤N≤100,000)이 주어지고, 이어서 N줄에 걸쳐 각 기둥의 좌표를 나타내는 정수 두 개가 주어진다. 좌표의 절댓값의 범위는 50,000을 넘을 수 없다.

www.acmicpc.net

 


아이디어

- 좌표 평면위의 여러 점들 중 가장 먼 거리의 두 점은 convex hull 위에 존재한다

  => convex hull (Graham's scan) 알고리즘

 

- convex hull에서 두 쌍의 연속한 두 점을 잡아 벡터를 만들고

  v1 = p[i+1] - p[i]     ... (p[i], p[i+1])

  v2 = p[j+1] - p[j]     ... (p[j], p[j+1])

  두 벡터의 ccw가 양수인 동안  j값을 증가시켜주며

  음수가 될 때 p[i]와 p[j] 사이의 거리가 최대값 보다 크다면 갱신한다.

=> 회전하는 캘리퍼스 알고리즘

 

회전하는 캘리퍼스의 경우 아래 수도코드로 보면 조금 더 이해가 잘 될 것이다

convex [] ... convex hull을 이루는 점들의 배열
sz = convexHull.size()

fartestDist = 0;
j = 1;

for (int i = 0; i < sz; i++) {
	n_i = (i + 1) % sz;
	for (;;) {
		n_j = (j + 1) % sz;
		px = convex[ni].x - convex[i].x; py = convex[ni].y - convex[i].y
		qx = convex[nj].x - convex[j].x; qy = convex[nj].y - convex[j].y

		if (ccw(px, py, qx, qy) > 0) j = j_next;
		else break;
	}

	dist = distance(convex[i], convex[j]);
	if (dist > fartestDist)
		fartestDist = dist;
}

 

증명은 기회가 되면 다음에 다루도록 하겠다

 


주의할 점

본인은 n = 1일 때, 전처리를 안 해주어 여러번 틀렸다


소스코드

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

typedef struct point {
    int x, y, p, q;
    point() : point(0, 0, 0, 0) {};
    point(int x_, int y_, int p_, int q_) : x(x_), y(y_), p(p_), q(q_) {}

    bool operator < (const struct point& z) const {
        if (1LL * q * z.p != 1LL * p * z.q) return 1LL * q * z.p < 1LL * p * z.q;
        if (y != z.y) return y < z.y;
        return x < z.x;
    }
} point;

long long ccw(const int px, const int py, const int qx, const int qy)
{
    return 1LL * px * qy - 1LL * qx * py;
}

long long ccw(const point& p1, const point& p2, const point& p3)
{
    return ccw(p2.x - p1.x, p2.y - p1.y, p3.x - p1.x, p3.y - p1.y);
}

long long dist(const point& p1, const point& p2)
{
    return 1LL * (p1.x - p2.x) * (p1.x - p2.x) + 1LL * (p1.y - p2.y) * (p1.y - p2.y);
}

int main()
{
    int n;
    int st[100001] = { 0 };
    point p[100001];

    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        int x, y;
        scanf("%d %d", &x, &y);
        p[i] = point(x, y, 0, 0);
    }

    if (n == 1) {
        puts("0");
        return 0;
    }

    sort(p, p + n);
    for (int i = 1; i < n; ++i) {
        p[i].p = p[i].x - p[0].x;
        p[i].q = p[i].y - p[0].y;
    }
    sort(p + 1, p + n);

    // Get ConvexHull using Graham's scan
    st[0] = 0; st[1] = 1;
    int pos = 2;
    for (int i = 2; i < n; ++i) {
        while (pos >= 2 && ccw(p[st[pos - 2]], p[st[pos - 1]], p[i]) <= 0) {
            pos--;
        }
        st[pos] = i;
        pos++;
    }

    // Rotating Calipers
    int j = 1;
    long long ans = 0;
    for (int i = 0; i < pos; ++i) {
        int ni = (i + 1) % pos, nj;
        for (;;) {
            nj = (j + 1) % pos;
            long long ret = ccw(p[st[ni]].x - p[st[i]].x, p[st[ni]].y - p[st[i]].y,
                                p[st[nj]].x - p[st[j]].x, p[st[nj]].y - p[st[j]].y);

            if (ret > 0) j = nj;
            else break;
        }
        if (i != j) {
            long long d = dist(p[st[i]], p[st[j]]);
            if (d > ans) ans = d;
        }
    }

    printf("%lld\n", ans);
    return 0;
}

 

 

 

 

 

공부한 것을 정리하기 위한 기록입니다.

틀린 부분이 있다면 부드럽게 알려주세요.

'PS > BOJ' 카테고리의 다른 글

[BOJ 3025] 돌 던지기  (0) 2020.09.02
[BOJ 16890] 창업  (0) 2020.08.31
[BOJ 16480] 외심과 내심은 사랑입니다  (0) 2020.07.28
[BOJ 18870] 좌표 압축  (0) 2020.07.16
[BOJ] 어른 상어  (0) 2020.06.09

댓글