BOJ 2162. ์ ๋ถ ๊ทธ๋ฃน
๐โโ๏ธ[Platinum V] ์ ๋ถ ๊ทธ๋ฃน - 2162
์ฑ๋ฅ ์์ฝ
๋ฉ๋ชจ๋ฆฌ: 2320 KB, ์๊ฐ: 156 ms
๋ถ๋ฅ
์๋ฃ ๊ตฌ์กฐ, ๋ถ๋ฆฌ ์งํฉ, ๊ธฐํํ, ์ ๋ถ ๊ต์ฐจ ํ์
์ ์ถ ์ผ์
2024๋ 3์ 9์ผ 21:08:15
๋ฌธ์ ์ค๋ช
N๊ฐ์ ์ ๋ถ๋ค์ด 2์ฐจ์ ํ๋ฉด์์ ์ฃผ์ด์ ธ ์๋ค. ์ ๋ถ์ ์ ๋์ ์ x, y ์ขํ๋ก ํํ์ด ๋๋ค.
๋ ์ ๋ถ์ด ์๋ก ๋ง๋๋ ๊ฒฝ์ฐ์, ๋ ์ ๋ถ์ ๊ฐ์ ๊ทธ๋ฃน์ ์ํ๋ค๊ณ ์ ์ํ๋ฉฐ, ๊ทธ๋ฃน์ ํฌ๊ธฐ๋ ๊ทธ ๊ทธ๋ฃน์ ์ํ ์ ๋ถ์ ๊ฐ์๋ก ์ ์ํ๋ค. ๋ ์ ๋ถ์ด ๋ง๋๋ค๋ ๊ฒ์ ์ ๋ถ์ ๋์ ์ ์ค์น๋ฏ์ด ๋ง๋๋ ๊ฒฝ์ฐ๋ ํฌํจํ๋ ๊ฒ์ผ๋ก ํ๋ค.
N๊ฐ์ ์ ๋ถ๋ค์ด ์ฃผ์ด์ก์ ๋, ์ด ์ ๋ถ๋ค์ ์ด ๋ช ๊ฐ์ ๊ทธ๋ฃน์ผ๋ก ๋์ด ์์๊น? ๋, ๊ฐ์ฅ ํฌ๊ธฐ๊ฐ ํฐ ๊ทธ๋ฃน์ ์ํ ์ ๋ถ์ ๊ฐ์๋ ๋ช ๊ฐ์ผ๊น? ์ด ๋ ๊ฐ์ง๋ฅผ ๊ตฌํ๋ ํ๋ก๊ทธ๋จ์ ์์ฑํด ๋ณด์.
์ ๋ ฅ
์ฒซ์งธ ์ค์ N(1 โค N โค 3,000)์ด ์ฃผ์ด์ง๋ค. ๋์งธ ์ค๋ถํฐ N+1๋ฒ์งธ ์ค์๋ ์ ๋์ ์ ์ขํ๊ฐ x1, y1, x2, y2์ ์์๋ก ์ฃผ์ด์ง๋ค. ๊ฐ ์ขํ์ ์ ๋๊ฐ์ 5,000์ ๋์ง ์์ผ๋ฉฐ, ์ ๋ ฅ๋๋ ์ขํ ์ฌ์ด์๋ ๋น์นธ์ด ํ๋ ์๋ค.
์ถ๋ ฅ
์ฒซ์งธ ์ค์ ๊ทธ๋ฃน์ ์๋ฅผ, ๋์งธ ์ค์ ๊ฐ์ฅ ํฌ๊ธฐ๊ฐ ํฐ ๊ทธ๋ฃน์ ์ํ ์ ๋ถ์ ๊ฐ์๋ฅผ ์ถ๋ ฅํ๋ค.
๋จผ์ ์ ๊ณผ ์ ๋ถ์ ๊ตฌ์กฐ์ฒด๋ก ๋ง๋ ๋ค.
struct Point {
long long x, y;
bool operator<=(Point const& p1) {
if (x == p1.x) {
return y <= p1.y;
}
return x <= p1.x;
}
};
struct Line {
Point p1, p2;
};
const int INF = 1234567890;
const int MAX = 10000;
// disjoint set ๊ธฐ๋ณธ ๊ฐ๋
int unf[MAX];
int ch[MAX];
int n;
vector<Line> lines;
์ ๋์จ ํ์ธ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ง ๋ค.
int Find(int u)
{
if (u == unf[u])
return u;
return unf[u] = Find(unf[u]);
}
void Merge(int u, int v)
{
u = Find(u);
v = Find(v);
if (u == v)
return;
unf[v] = u;
}
CCW ์๊ณ ๋ฆฌ์ฆ์ ๋ค์๊ณผ ๊ฐ๋ค.
long long CCW(const Point& p1, const Point& p2, const Point& p3)
{
long long res = (p1.x * p2.y + p2.x * p3.y + p3.x * p1.y) - (p2.x * p1.y + p3.x * p2.y + p1.x * p3.y);
// ํ๋ ฌ์์ ํตํด์ ๊ตฌํ๊ธฐ
// int determinant = (p2.x*p3.y - p2.y*p3.x) - \
// (p1.x*p3.y - p1.y*p3.x) + \
// (p1.x*p2.y - p1.y*p2.x);
if (res > 0)
return 1; //๋ฐ์๊ณ
else if (res < 0)
return -1; //์๊ณ
else return 0;
}
bool isCross(Line& l1, Line& l2)
{
long long std1, std2;
std1 = CCW(l1.p1, l1.p2, l2.p1) * CCW(l1.p1, l1.p2, l2.p2);
std2 = CCW(l2.p1, l2.p2, l1.p1) * CCW(l2.p1, l2.p2, l1.p2);
if (std1 <= 0 && std2 <= 0) {
if (std1 == 0 && std2 == 0) { //์ ๋ถ์ด ์ผ์ง์ ์ธ ๊ฒฝ์ฐ
if (l1.p2 <= l1.p1) swap(l1.p1, l1.p2);
if (l2.p2 <= l2.p1) swap(l2.p1, l2.p2);
return l1.p1 <= l2.p2 && l2.p1 <= l1.p2;
}
else return true; //์ผ์ง์ ์ด ์๋๋ฉด ๊ต์ฐจํจ
}
else return false; //CCW๊ฐ ๊ฐ์ ๋ฐฉํฅ์ด ์์ผ๋ฉด
}
๊ฐ ์ ๋ถ์ ๊ทธ๋ฆฌ๋ฉด์ ๊ณ์น๋ ๋ถ๋ถ์ด ์๊ธฐ๋ฉด ๊ทธ๋ฃน์ผ๋ก ๋ง๋ ๋ค.
unf๋ฐฐ์ด์ ๊ธฐ๋กํ๊ณ ch๋ฐฐ์ด์ ๊ทธ๋ฃน์ ๊ฐ์๋ฅผ ์ ์ฅํ๋ค.
void solve()
{
cin >> n;
lines = vector<Line>(n + 1);
long long x1, x2, y1, y2;
for (int i = 1; i <= n; i++)
{
cin >> x1 >> y1 >> x2 >> y2;
lines[i].p1 = { x1, y1 };
lines[i].p2 = { x2, y2 };
// ์ฒ์์ ์๊ธฐ ์์ ์ด ๊ทธ๋ฃน์ ๋์ฅ.
unf[i] = i;
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
if (i == j)
continue;
if (isCross(lines[i], lines[j]))
{
// ๊ต์ฐจํ ๊ฒฝ์ฐ ๊ทธ๋ฃน์ ์ถ๊ฐ
Merge(i, j);
}
}
}
int cnt = 0, maxCnt = 0;
for (int i = 1; i <= n; ++i)
{
ch[Find(i)]++;
}
for (int i = 1; i <= n; ++i)
{
if (ch[i] == 0)
continue;
cnt++;
maxCnt = max(maxCnt, ch[i]);
}
//for (int i = 1; i <= n; ++i)
//{
// cout << unf[i] << " ";
//}
//cout << endl;
//for (int i = 1; i <= n; ++i)
//{
// cout << ch[i] << " ";
//}
//cout << endl;
cout << cnt << '\n';
cout << maxCnt << '\n';
}
6
1 0 3 0
1 1 3 1
3 1 2 3
2 3 1 1
0 2 2 4
2 0 0 3
์ด๋ฐ ์์๊ฐ ์์ ๋ ์ต์ข ์ ์ผ๋ก unf์ ch๋ฐฐ์ด์ ๋ค์๊ณผ ๊ฐ์ด ๋์จ๋ค.
๐ํ์ด
Union & Find์ CCW ์๊ณ ๋ฆฌ์ฆ์ ์์ ๋ฌธ์ ์๋ค.
๐์ ์ฒด ์ฝ๋
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include<iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
struct Point {
long long x, y;
bool operator<=(Point const& p1) {
if (x == p1.x) {
return y <= p1.y;
}
return x <= p1.x;
}
};
struct Line {
Point p1, p2;
};
const int INF = 1234567890;
const int MAX = 10000;
// disjoint set ๊ธฐ๋ณธ ๊ฐ๋
int unf[MAX];
int ch[MAX];
int n;
vector<Line> lines;
int Find(int u)
{
if (u == unf[u])
return u;
return unf[u] = Find(unf[u]);
}
void Merge(int u, int v)
{
u = Find(u);
v = Find(v);
if (u == v)
return;
unf[v] = u;
}
long long CCW(const Point& p1, const Point& p2, const Point& p3)
{
long long res = (p1.x * p2.y + p2.x * p3.y + p3.x * p1.y) - (p2.x * p1.y + p3.x * p2.y + p1.x * p3.y);
// ํ๋ ฌ์์ ํตํด์ ๊ตฌํ๊ธฐ
// int determinant = (p2.x*p3.y - p2.y*p3.x) - \
// (p1.x*p3.y - p1.y*p3.x) + \
// (p1.x*p2.y - p1.y*p2.x);
if (res > 0)
return 1; //๋ฐ์๊ณ
else if (res < 0)
return -1; //์๊ณ
else return 0;
}
bool isCross(Line& l1, Line& l2)
{
long long std1, std2;
std1 = CCW(l1.p1, l1.p2, l2.p1) * CCW(l1.p1, l1.p2, l2.p2);
std2 = CCW(l2.p1, l2.p2, l1.p1) * CCW(l2.p1, l2.p2, l1.p2);
if (std1 <= 0 && std2 <= 0) {
if (std1 == 0 && std2 == 0) { //์ ๋ถ์ด ์ผ์ง์ ์ธ ๊ฒฝ์ฐ
if (l1.p2 <= l1.p1) swap(l1.p1, l1.p2);
if (l2.p2 <= l2.p1) swap(l2.p1, l2.p2);
return l1.p1 <= l2.p2 && l2.p1 <= l1.p2;
}
else return true; //์ผ์ง์ ์ด ์๋๋ฉด ๊ต์ฐจํจ
}
else return false; //CCW๊ฐ ๊ฐ์ ๋ฐฉํฅ์ด ์์ผ๋ฉด
}
void solve()
{
cin >> n;
lines = vector<Line>(n + 1);
long long x1, x2, y1, y2;
for (int i = 1; i <= n; i++)
{
cin >> x1 >> y1 >> x2 >> y2;
lines[i].p1 = { x1, y1 };
lines[i].p2 = { x2, y2 };
// ์ฒ์์ ์๊ธฐ ์์ ์ด ๊ทธ๋ฃน์ ๋์ฅ.
unf[i] = i;
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
if (i == j)
continue;
if (isCross(lines[i], lines[j]))
{
// ๊ต์ฐจํ ๊ฒฝ์ฐ ๊ทธ๋ฃน์ ์ถ๊ฐ
Merge(i, j);
}
}
}
int cnt = 0, maxCnt = 0;
for (int i = 1; i <= n; ++i)
{
ch[Find(i)]++;
}
for (int i = 1; i <= n; ++i)
{
if (ch[i] == 0)
continue;
cnt++;
maxCnt = max(maxCnt, ch[i]);
}
//for (int i = 1; i <= n; ++i)
//{
// cout << unf[i] << " ";
//}
//cout << endl;
//for (int i = 1; i <= n; ++i)
//{
// cout << ch[i] << " ";
//}
//cout << endl;
cout << cnt << '\n';
cout << maxCnt << '\n';
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
freopen("input.txt", "rt", stdin);
solve();
return 0;
}