본문 바로가기

BOJ

[BOJ 10523] 직선 찾기

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

 

10523번: 직선 찾기

입력 예제 1에서 (0, 0) / (3, 3) / (10, 10)을 지나는 직선을 찾을 수 있다. 2.75개 이상의 점을 지났으니 그러한 직선이 있다고 볼 수 있다.

www.acmicpc.net

Tag : random

 

문제요약

N개의 점이 이차원 좌표평면 위에 있을 때 이 중 p퍼센트 이상의 점을 지나는 직선이 있는지 판별하라.

 

풀이

답이 possible이면서 시간복잡도 상으로 최악일 경우를 생각해보자.

k = \( \lfloor \frac{n \times p}{100} \rfloor \)일 때

k개의 점을 지나는 직선이 딱 1개 있는 경우일 것이다.

 

서로 다른 두 점을 아무렇게나 한번 골라서 이 두 점을 지나는 직선이 답에 해당하는 직선일 확률은 다음과 같다.

 

전체 경우 = \(\binom{n}{2}\)

직선에 포함되는 점을 고르는 경우 = \( \binom{ k }{ 2} \)

 

따라서 \( \frac{\binom{ k }{ 2}}{\binom{n}{2}} \)가 아무렇게나 서로 다른 두점을 골라서 직선을 만들어봤을 때

그 직선이 맞는 답에 해당하는 직선일 확률이고

틀릴 확률은 \( \frac{\binom{n}{2} - \binom{ k }{ 2}}{\binom{n}{2}} \)가 된다.

이것이 최대가 되는 경우는 당연히 k가 가장 작은 경우일 것이고

p의 최소인 20을 대입하면 \(\frac{\binom{n}{2}}{10}\)이다.

이 k를 대입하면 틀릴 확률의 최대는 \( \frac{4}{5} \)가 된다. 

이것을 대충 100번만 반복해도 틀릴 확률은 약 2e-8%가 되기 때문에

랜덤으로 두 점을 뽑아보는 풀이가 통과한다.

 

랜덤이라 그런지 똑같은 횟수를 돌렸는데 한번은 틀리고 한번은 맞는 신기한 경험을 했다

맞은사람 1등 기분최고

 

 

전체코드

#include "bits/stdc++.h"
#define endl '\n'

using namespace std;
using ll = long long;

struct RAND {
    random_device rg;
    mt19937 rd;
    RAND() { rd.seed(rg()); }
    int nxt(int l, int r) { return uniform_int_distribution<int>(l, r)(rd); }
} rnd;

ll n, pp, f = 0;
ll x[101010], y[101010];

#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int z[36];
char*c=(char*)mmap(0,z[12],1,2,0,fstat(0,(struct stat *)z));
struct fastio {
    inline int f(){int x=0;bool e;c+=e=*c=='-';while(*c>='0')x=10*x+*c++-'0';c++;return e?-x:x;}
} IO;

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    
    n = IO.f(); pp = IO.f();
    if(n == 1) return cout << "possible" << endl, 0;
    for(int i=1; i<=n; i++) x[i] = IO.f(), y[i] = IO.f();
    for(int t=1; t<=150; t++) {
        ll p = rnd.nxt(1, n - 1);
        ll q = rnd.nxt(p + 1, n);
        ll a = y[p] - y[q];
        ll b = x[p] - x[q];
        ll cnt = 0;
        for(int i=1; i<=n; i++) {
            if(a * (x[i] - x[p]) == b * (y[i] - y[p])) cnt++;
        }
        if(cnt >= (n * pp + 99) / 100) {
            f = 1;
            break;
        }
    }
    if(f) cout << "possible" << endl;
    else cout << "impossible" << endl;
}

'BOJ' 카테고리의 다른 글

[BOJ 16474] 이상한 전깃줄  (0) 2022.01.13
[BOJ 23578] 비 오는 날  (0) 2022.01.13
[BOJ 13255] 동전 뒤집기  (0) 2022.01.11
[BOJ 13257] 생태학  (0) 2022.01.11
[BOJ 1167] 트리의 지름  (3) 2022.01.08