Game Develop

[Algorithm]Baekjoon 2162번 : 선분 그룹 본문

Algorithm/Baekjoon

[Algorithm]Baekjoon 2162번 : 선분 그룹

MaxLevel 2024. 2. 11. 05:36

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

 

2162번: 선분 그룹

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

www.acmicpc.net

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 
 
using namespace std;
 
typedef pair<intint> vector2D;
typedef pair<intint> point;
typedef pair<point, point> lineSegment;
 
int n, a, b, c, d;
vector<lineSegment> lineSegments;
int parents[3000= { 0 };
int groupSizes[3000= { 0 };
 
int FindParent(int node)
{
    if (parents[node] == node) return node;
    return parents[node] = FindParent(parents[node]);
}
 
bool CompareParents(int a, int b)
{
    a = FindParent(a);
    b = FindParent(b);
 
    if (a == b) return true;
    return false;
}
 
void UnionParents(int a, int b)
{
    a = FindParent(a);
    b = FindParent(b);
 
    if (a < b)
    {
        parents[b] = a;
        groupSizes[a] += groupSizes[b];
        groupSizes[b] = 0;
    }
    else
    {
        parents[a] = b;
        groupSizes[b] += groupSizes[a];
        groupSizes[a] = 0;
    }
}
 
int CCW(point& s1, point& p1, point& p2)
{
    vector2D v1 = { p1.first - s1.first, p1.second - s1.second };
    vector2D v2 = { p2.first - s1.first, p2.second - s1.second };
 
    long long crossResult = (long long)v1.first * v2.second - (long long)v1.second * v2.first;
 
    if (crossResult < 0return 1;
    else if (crossResult > 0return -1;
    return 0;
}
 
bool Compare(point& p1, point& p2)
{
    if (p1.first == p2.first)
    {
        return p1.second <= p2.second;
    }
 
    return p1.first <= p2.first;
}
 
void Swap(point& p1, point& p2)
{
    point temp = p1;
    p1 = p2;
    p2 = temp;
}
 
bool IsIntersection(lineSegment& l1, lineSegment& l2) // 두 선분이 교차하는지 검사.
{
    int ccwResult1 = CCW(l1.first, l2.first, l2.second) * CCW(l1.second, l2.first, l2.second);
    int ccwResult2 = CCW(l2.first, l1.first, l1.second) * CCW(l2.second, l1.first, l1.second);
 
    if (ccwResult1 == 0 && ccwResult2 == 0// 둘 다 0이면 두 선분이 일단 한 직선위에 존재한다는 것.
    {
        if (Compare(l1.first, l1.second) == false)
        {
            swap(l1.first, l1.second);
        }
 
        if (Compare(l2.first, l2.second) == false)
        {
            swap(l2.first, l2.second);
        }
 
        return Compare(l2.first, l1.second) && Compare(l1.first, l2.second);
    }
 
    return ccwResult1 <= 0 && ccwResult2 <= 0;
}
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    cin >> n;
 
    for (int i = 0; i < n; ++i)
    {
        cin >> a >> b >> c >> d;
 
        lineSegments.push_back({ { a,b }, { c,d } });
        groupSizes[i] = 1;
        parents[i] = i;
    }
 
    for (int i = 0; i < n; ++i)
    {
        for (int j = i + 1; j < n; ++j)
        {
            lineSegment& a = lineSegments[i];
            lineSegment& b = lineSegments[j];
 
            if (IsIntersection(a, b)) // 이어져있고
            {
                if (CompareParents(i, j) == false// 아직 집합에 안 합쳤으면
                {
                    UnionParents(i, j); // 합친다.
                }
            }
        }
    }
 
    int groupCount = 0;
    int maxGroupSize = 0;
 
    for (int i = 0; i < n; ++i)
    {
        if (groupSizes[i] > 0++groupCount;
        maxGroupSize = max(maxGroupSize, groupSizes[i]);
    }
 
    cout << groupCount << endl << maxGroupSize;
}
 
 
 
 
 
cs

 

이전에 풀었던 선분 교차 2에 Union-Find를 결합한 문제이다. 연결된 선분의 그룹의 개수와 최대 그룹의 크기를 구하는 문제이기 때문에 Union-Find를 사용했다. 선분교차에 대한에 특이사항이 추가된건 없기 때문에 그대로 사용하면 된다.