문제 풀이/백준
백준 - 선분 그룹 (2162) [C++]
JJJaewon
2024. 4. 18. 16:07
반응형
이 문제는 유니온 파인드, CCW 알고리즘을 사용해서 풀었다.
CCW 알고리즘을 처음 알게 된 문제였다. CCW 알고리즘은 간단히 말해서 외적을 통해 세 점의 방향성을 찾는 알고리즘인데, 이를 이용하여 두 선분간의 교점 여부를 파악하는데 사용했다.
또한 그룹 관련 요구사항도 존재하므로 이는 유니온 파인드로 쉽게 해결할 수 있었다.
각 선분에 대해 다른 선분들을 루프를 돌기 때문에 O(N^2) 시간 복잡도가 걸리지만, 선분이 최대 3,000개이므로 충분히 2초 안에 풀 수 있다.
#include <iostream>
#include <vector>
#include <map>
#include <utility>
#include <algorithm>
using namespace std;
#define COUNTER 1
#define LINE 0
#define CLOCK -1
struct Line {
int x1;
int y1;
int x2;
int y2;
};
int ccw(int x1, int y1, int x2, int y2, int x3, int y3) {
int result = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
if (result > 0) {
return COUNTER;
} else if (result == 0) {
return LINE;
} else {
return CLOCK;
}
}
vector<Line> lines;
int parent[3000];
int N;
void init() {
for (int i = 0; i < N; i++) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] != x) {
return parent[x] = find(parent[x]);
}
return x;
}
bool isIntersact(int aIndex, int bIndex) {
Line &a = lines[aIndex];
Line &b = lines[bIndex];
int result1 = ccw(a.x1, a.y1, a.x2, a.y2, b.x1, b.y1);
int result2 = ccw(a.x1, a.y1, a.x2, a.y2, b.x2, b.y2);
int result3 = ccw(b.x1, b.y1, b.x2, b.y2, a.x1, a.y1);
int result4 = ccw(b.x1, b.y1, b.x2, b.y2, a.x2, a.y2);
int res12 = result1 * result2;
int res34 = result3 * result4;
if (res12 == 0 && res34 == 0) {
pair<int, int> tmp1 = { a.x1, a.y1 };
pair<int, int> tmp2 = { a.x2, a.y2 };
pair<int, int> tmp3 = { b.x1, b.y1 };
pair<int, int> tmp4 = { b.x2, b.y2 };
if (tmp1 > tmp2) {
swap(tmp1, tmp2);
}
if (tmp3 > tmp4) {
swap(tmp3, tmp4);
}
return tmp3 <= tmp2 && tmp1 <= tmp4;
}
return (res12 <= 0 && res34 <= 0);
}
void merge(int a, int b) {
int aRoot = find(a);
int bRoot = find(b);
if (aRoot == bRoot) {
return;
}
if (aRoot < bRoot) {
parent[bRoot] = aRoot;
} else {
parent[aRoot] = bRoot;
}
}
int groupCnt[3000];
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> N;
init();
for (int i = 0; i < N; i++) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
Line newLine = { x1, y1, x2, y2 };
lines.push_back(newLine);
}
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (isIntersact(i, j)) {
merge(i, j);
}
}
}
for (int i = 0; i < N; i++) {
int root = find(i);
groupCnt[root]++;
}
int ans1 = 0;
int ans2 = -1;
for (int i = 0; i < N; i++) {
int num = groupCnt[i];
if (num > 0) {
ans1++;
ans2 = max(ans2, num);
}
}
cout << ans1 << '\n';
cout << ans2 << '\n';
return 0;
}
반응형