ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 3679 - 단순 다각형
    알고리즘/백준 2025. 1. 25. 02:28

    문제

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

     

    풀이

    오랫만에 보는 Convex hull...? 비슷한 문제

    원래는 스택에 하나씩 push/pop하면서 Convex hull을 구해줘야하는데, 이는 모든 점을 사용해서 다각형을 만들어 주기만 하면 된다.

     

    시작점0을 기준으로 반시계 기준으로 정렬하고 점을 차례로 이으면 좌측(N=5)그림과 같이 다각형을 그릴 수 있다.

    하지만 우측(N=7)그림과 같이 마지막 점들이 직선을 이루고 있는 경우 역순으로 이어줘야한다.

    이경우만 잘 고려해서 cross(0, N - 1, index)가 0일 경우부터는 역순으로 이어주면된다.

    좌 / 우

     

    코드

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    #include <map>
    #include <stack>
    using namespace std;
    struct Dot {
        int x, y;
        bool operator<(const Dot& o) const {
            if (x < o.x) return true;
            else if (x > o.x) return false;
            return y < o.y;
        }
    };
    vector<Dot> v;
    int N, T;
    vector<Dot> answer;
    map<Dot, int> indexMap;
    int cross(Dot a, Dot b, Dot c)
    {
        // a > b > c
        Dot l1 = { b.x - a.x, b.y - a.y };
        Dot l2 = { c.x - b.x, c.y - b.y };
        int r = l1.x * l2.y - l1.y * l2.x;
        if (r < 0) return -1;
        else if (r > 0) return 1;
        return 0;
    }
    int getDistance(Dot a)
    {
        return (v[0].x - a.x) * (v[0].x - a.x) + (v[0].y - a.y) * (v[0].y - a.y);
    }
    bool cmp(Dot a, Dot b) {
        int r = cross(v[0], a, b);
        if (r > 0) return 1;
        else if (r == 0) return getDistance(a) < getDistance(b);
        return 0;
    }
    void solve()
    {
        v.clear();
        indexMap.clear();
        answer.clear();
        cin >> N;
        int a, b, ta, tb;
        cin >> a >> b;
        v.push_back({ a, b });
        for (int i = 1; i < N; ++i) {
            //dot save
            //가장 x,y가 작은 시작 점 찾기
            cin >> a >> b;
            indexMap[{a, b}] = i;
            if (a < v[0].x) {
                ta = v[0].x;
                tb = v[0].y;
                v[0] = { a, b };
                v.push_back({ ta, tb });
            }
            else if (a == v[0].x && b < v[0].y) {
                ta = v[0].x;
                tb = v[0].y;
                v[0] = { a, b };
                v.push_back({ ta, tb });
            }
            else {
                v.push_back({ a, b });
            }
        }
    
        // 반시계 정렬
        sort(v.begin() + 1, v.end(), cmp);
        answer.push_back(v[0]);
        answer.push_back(v[1]);
        int rflag = 0;
        for (int i = 2; i < v.size() - 1; ++i) {
            if (cross(v[0], v[v.size() - 1], v[i]) == 0) {
                for (int j = v.size() - 1; j >= i; --j) {
                    answer.push_back(v[j]);
                }
                rflag = 1;
                break;
            }
            answer.push_back(v[i]);
        }
        if (rflag == 0) answer.push_back(v[v.size() - 1]);
        for (int i = 0; i < answer.size(); ++i) {
            cout << indexMap[answer[i]] << " ";
        }
        cout << "\n";
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        cin >> T;
        for (int i = 0; i < T; ++i) solve();
        return 0;
    }

    '알고리즘 > 백준' 카테고리의 다른 글

    [백준] 12752번 - 도시들  (1) 2025.01.04
    [백준] 5670번 - 휴대폰 자판  (0) 2024.12.22
    [백준] 1854 - K번째 최단경로 찾기  (0) 2024.12.07
    [백준] 11437 - LCA  (1) 2024.11.27
    [백준] 2679번 - 맨체스터의 도로  (1) 2024.09.17
Designed by Tistory.