이어서 입력되는 N개의 줄에는 두개의 정수 Xi Yi 가 입력된다. i번째 적의 위치 좌표는 (Xi, Yi)이다. (−10^9 ≤ Xi, Yi ≤ 10^9) 단, 같은 위치에 두 명의 적이 있을수는 없다.
작전 지역은 평지이므로 높이는 신경쓰지 않아도 된다.
출력
맥크리는 총알 두발로 적들을 없애려 한다. 이 계획의 성공 여부를 출력하라. 성공할 시 "success"를 실패할 경우 "failure"를 출력하면 된다.
입력 예시
6
-1 0
0 0
1 0
-1 1
0 2
1 1
출력 예시
failure
풀이
우선 다음과 같은 접근법을 생각해 볼 수 있다.
success case에서는, 두 선분으로 모든 점들을 포함할 수 있다.
즉 두 점을 뽑고, 두 점과 동일한 선분 내에 위치한 모든 점들을 찾는다.
CCW 방식을 사용했을 때, 동일 선분 내라면 CCW값이 0이 된다.
앞선 search 과정에서 뽑히지 않은 점들에 대하여 같은 방식으로 동일 선분 내의 모든 점들을 찾는다.
만약 두 번의 search 과정에서 남은 점이 존재한다면, 두 선분으로 모든 점을 포함할 수 없다. 즉 failure를 출력한다. 남은 점이 없다면 두 선분으로 모든 점을 포함시켰으므로 success를 출력한다.
하지만 여지없이 wa를 받았다. 너무 억울해서(?) 문제 분류를 보고 그 해답을 바로 찾아낼 수 있었다.
우리가 search 초반에 두 점을 뽑을 때, 두 점이 다른 선분 내에 위치할 경우를 생각할 수 있다.
이러한 경우, search 시 최대 3개의 선분을 찾아내 버리므로 failure로 분류되어 버린다.
다시 돌아가서, 우리가 임의의 두 점을 뽑을 때, 두 점이 최적화된 한 직선 내에 뽑힐 확률을 생각하면 최소 0.5라는 사실을 알 수 있다. 즉 좌표를 랜덤하게 섞고, 그 랜덤한 좌표 중 두 점을 뽑는 과정을 반복한다. 한 번이라도 success라면 두 직선으로 잇는 것이 가능하다. 이 랜덤 횟수가 10일 경우, 실패할 확률(두 점을 모두 이을 수 있음에도 불구하고 모든 추출이 실패할 경우)는 1 - 0.5^10으로, 매우 적다. 즉 무작위화가 포인트였다.
풀이 코드
import random
import sys
input = sys.stdin.readline
N = int(input())
coord_list = [tuple(map(int, input().split())) for _ in range(N)]
if N < 4 :
print("success")
exit()
def ccw(a, b, c) :
return (a[0]*b[1] + b[0]*c[1] + c[0]*a[1]) - (a[1]*b[0] + b[1]*c[0] + c[1]*a[0])
def search(coord, ret) :
next_coord = []
for _coord in coord :
if ccw(ret[-2], ret[-1], _coord) != 0 :
next_coord.append(_coord)
return next_coord
flg = False
for _ in range(10) :
tmp = coord_list[:]
for i in range(2) :
ret = random.sample(tmp, 2)
tmp = search(tmp, ret)
if len(tmp) < 2-i :
flg = True
break
if flg :
break
print("success" if flg else "failure")
p.s. 밑의 len(tmp) < 2-i를 붙인 이유는 random.sample의 k 인자 때문이다. k인자값이 population 값보다 크다면 valueerror를 일으키므로, 첫 번째 순회 후 남은 좌표 개수가 2 미만, 두 번째 순회 후 남은 좌표 개수가 1 미만일 경우 success하도록 설정하였다.