๐Ÿ™‡โ€โ™€๏ธ[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๋ฐฐ์—ด์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜์˜จ๋‹ค.

image

image

๐Ÿš€ํ’€์ด

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;
}

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ: