알고리즘/atcoder90제
앳코더90 - 017 - Crossing Segments(★7)
b1ackhand
2024. 11. 9. 17:37
https://atcoder.jp/contests/typical90/tasks/typical90_q
017 - Crossing Segments(★7)
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
원위에 N개의 점이 있고 M개의 선분이 있을 때, 각각의 선분을 이었을 때 교차점의 개수를 구하여라.
예제 1번의 예시를 그림으로 그리면 위와 같다.
먼저, 소문제 부터 풀어보자. 우리가 교차점이 생길려면은 다음과 같은 조건을 충족해야된다. 원에서 선분이 그려질 때 a,b를 잇는 직선과 c,d를 잇는 직선이 있다 할때, 하나의 점 c가 a,b 사이에 있고 다른 하나의 점 d가 a,b 외부에 있을 때 교차점이 생긴다. 이를 원이 아니라 펼쳐져 수직선위에 있다고 생각해도 무방하다. 이를 수식으로 바꿔서 코드로 표현하면 아래와 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
#include <unordered_set>
#include <numeric>
#include <random>
#include <iostream>
#include <unordered_map>
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rep1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef vector<int> vi;
typedef vector<long long> vll;
const int INF = 2000000000;
const double pi = 3.14159265358979;
const int MOD = 100000;
void yesno(bool a)
{
if (a)
cout << "YES\n";
else
cout << "NO\n";
}
int N, M;
vector<pii> v;
int ans = 0;
int visited[300002];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> N >> M;
rep(i, M)
{
int a, b;
cin >> a >> b;
if (a > b)
swap(a, b);
v.push_back({ a,b });
}
sort(v.begin(), v.end());
rep(i, M)
{
pii cur = v[i];
for(int j = 0;j < i;j++)
{
pii dif = v[j];
if (
(cur.first < dif.first && dif.first < cur.second) &&
(dif.second < cur.first || cur.second < dif.second)
)
{
ans++;
}
else if (
(cur.first < dif.second && dif.second < cur.second) &&
(dif.first < cur.first || cur.second < dif.first)
)
{
ans++;
}
}
}
cout << ans;
return 0;
}
선분의 시작점을 기준으로 정렬한 후 O(N^2)으로 각각 확인해준다. 하지만 이 같은 경우에는 나머지 과제를 해결 할 수 없다. 선분이 추가 될 때 마다 해당 선분이 특정 구간에 들어 갈 수 있는지 확인하는 방법을 세그먼트 트리를 이용해서 해결 하려 했으나.. 뭔가 잘 안됐다.
정해에서는 위 방법을 최적화 하기 어렵기에 여사건을 구하고 전체 경우의 수에서 빼는 방법으로 설명한다.