DAMPER's blog

2162. 선분 그룹 본문

Problem Solving/BOJ 문제풀이

2162. 선분 그룹

DAMPER 2022. 1. 9. 17:11
728x90

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

 

2162번: 선분 그룹

첫째 줄에 N(1 ≤ N ≤ 3,000)이 주어진다. 둘째 줄부터 N+1번째 줄에는 양 끝점의 좌표가 x1, y1, x2, y2의 순서로 주어진다. 각 좌표의 절댓값은 5,000을 넘지 않으며, 입력되는 좌표 사이에는 빈칸이 하

www.acmicpc.net

문제 설명

선분의 양끝의 점 2개를 N번 입력받고 선분끼리 만나면 선분 그룹안에 속한다고 한다.

이 때, 선분 그룹의 갯수와 크기가 가장 큰 그룹의 선분 갯수를 출력하면 된다.

 

여기서 필요한 것은 두 선분이 만나는 것을 체크하는 것과 그룹을 만드는 것이다.

두 선분이 만나는지 아닌지를 판단하는 CCW와 그룹을 만드는 Disjoint-Set을 사용했다.

 

평소에 Disjoint-Set을 구현할 때 rank를 잘 사용하지 않지만 이번에는 그룹에 속한 선분의 갯수를 구하기 위해서 rank 배열을 사용했다. 별로 쓸모 없을 줄 알았는데 생각보다 유용한 것 같다.

 

시간 복잡도는 \( O(N^2log^*N) \)  으로 서로다른 두 선분\((O(N^2))\)을 CCW로 판단하여 선분이 교차하면 merge\( (O(log^*N)) \) 를 한다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <bits/stdc++.h>
 
using namespace std;
 
#define endl '\n'
#define int long long
 
using pii = pair<intint>;
 
const double EPS = 1e-9;
const int dx[] = {1-100};
const int dy[] = {001-1};
 
class DisjointSet
{
public:
    vector<int> parent, rank;
    DisjointSet(){}
    DisjointSet(int size)
    {
        parent.resize(size+10);
        rank.resize(size+11);
        for(size_t i=0;i<parent.size();i++)
            parent[i] = i;
    }
    int find(int v)
    {
        if(parent[v] == v) return v;
        return parent[v] = find(parent[v]);
    }
    bool merge(int u, int v)
    {
        u = find(u);
        v = find(v);
        if(u == v) return false;
        if(rank[v] >= rank[u])
        {
            parent[u] = v;
            rank[v] += rank[u];
        }
        else
        {
            parent[v] = u;
            rank[u] += rank[v];
        }
        return true;
    }
};
 
int ccw(pii a, pii b, pii c)
{
    int ans = (a.first * b.second + b.first * c.second + c.first * a.second) - (a.second * b.first + b.second * c.first + c.second * a.first);
    if(ans > 0return 1;
    else if(ans < 0return -1;
    return 0;    
}
 
bool check(pii a, pii b, pii c, pii d)
{
    int abc = ccw(a, b, c);
    int abd = ccw(a, b, d);
    int cda = ccw(c, d, a);
    int cdb = ccw(c, d, b);
    if(abc * abd == 0 && cda * cdb == 0)
    {
        if(a > b) swap(a, b);
        if(c > d) swap(c, d);
        return a <= d && c <= b;
    }
    return abc * abd <= 0 && cda * cdb <= 0;
}
 
int32_t main()
{
    cin.sync_with_stdio(NULL);
    cin.tie(NULL);
    cout.tie(NULL);
 
    int n;
    cin >> n;
    DisjointSet DS(n);
    vector<pair<pii, pii>> v(n);
    for(int i=0;i<n;i++)
    {
        cin >> v[i].first.first >> v[i].first.second >> v[i].second.first >> v[i].second.second;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(check(v[i].first, v[i].second, v[j].first, v[j].second))
            {
                DS.merge(i, j);
            }
        }
    }
    int num = 0, mx = 0;
    for(int i=0;i<n;i++)
    {
        if(DS.find(i) == i)
        {
            num++;
            mx = max(mx, DS.rank[i]);
        }
    }
 
    cout << num << endl << mx;
 
    return 0;
}
cs

 

 

 

 

 

 

728x90

'Problem Solving > BOJ 문제풀이' 카테고리의 다른 글

1007. 벡터 매칭  (0) 2022.07.04
13140. Hello World!  (0) 2022.01.13
16724. 피리 부는 사나이  (0) 2022.01.08
9527. 1의 개수 세기  (0) 2022.01.05
2342. Dance Dance Revolution  (0) 2022.01.04