728x90
http://wwww.acmicpc.net/problem/1007
# 조건
- 평면 상에 N개의 점이 찍혀있고, 그 점을 집합 P라고 하자.
- 집합 P의 벡터 매칭은 벡터의 집합인데, 모든 벡터는 집합 P의 한 점에서 시작해서, 또 다른 점에서 끝나는 벡터의 집합이다.
- 또, P에 속하는 모든 점은 한 번씩 쓰여야 한다.
- 벡터 매칭에 있는 벡터의 개수는 P에 있는 점의 절반이다.
- 평면 상의 점이 주어졌을 때, 집합 P의 벡터 매칭에 있는 벡터의 합의 길이의 최솟값을 출력하는 프로그램을 작성하시오.
# 접근 방법
- 우선 벡터를 구하는 방법
- v1 = (x2-x1, y2-y1)
- v2 = (x4-x3, y4-y3)
- 벡터 사이의 합은
- v1 + v2 = (x2+x4 -x1-x3, y2+y4 -y1-y3)
- |v1 + v2| = sqrt((x2+x4 -x1-x3)^2 + (y2+y4 -y1-y3)^2)
- 이 때, 위의 벡터 사이의 합 공식을 x와 y를 나눠서 본다면
- 각각 2개는 더하고 2개는 뺄 수 있다.
- 즉, 벡터들의 끝 지점에 있는 점들을 모두 합한 것과, 시작 지점에 있는 점들을 모두 뺀 것이 N개의 점으로 만든 N/2 개의 벡터들을 합하여 만든 벡터의 값과 같다
- v1 + v2 + v3 + ... + vN/2 = (x2+x4+x6+...+xN -x1-x3-x5...-xN-1,y2+y4+y6+...+yN -y1-y3-y5...-yN-1)
- N이 20까지만 주어지기 때문에, 전체 탐색 후 최소값을 구해도 된다.
- sum_dot 함수를 이용해 선택된 점의 좌표들을 더해준다.
- 10개의 점을 고르는 경우의 수를 조합으로 구한 후
- 빼야하는 절반의 점들의 좌표합을 더하고 나머지 점들의 좌표합을 빼서 구해주면 된다.
- 이 때, 전체 합에서 절반의 점들의 값을 안빼주고 계산하는 경우 절반의 점 값의 합을 x 2 해주어야 한다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from itertools import combinations
def sum_dot(mat):
res = [0,0]
for i in mat:
res[0] += i[0]
res[1] += i[1]
return res
T = int(input())
for _ in range(T):
N = int(input())
dot = [[*map(int, input().split())] for _ in range(N)]
total_sum = sum_dot(dot)
result = sys.maxsize
# 빼줄 점들 구하기
minus_dot = list(combinations(dot, N//2))
for i in minus_dot:
cur = sum_dot(i)
# 전체 좌표에서 빼주지 않았으므로 현재 구하는 합도 *2를 해준다.
result = min(result, ((2*cur[0] - total_sum[0])**2 + (2*cur[1] - total_sum[1])**2)**0.5)
print(result)
728x90
'ALGORITHM > 수학, 기하학' 카테고리의 다른 글
[백준 2166번] 파이썬 - 다각형의 면적 (0) | 2023.01.19 |
---|---|
[백준 2568번] 파이썬 - 전깃줄2 (0) | 2023.01.14 |
[백준 3096번] 파이썬 - 영화제 (0) | 2023.01.03 |
[백준 17087번] 파이썬 - 숨바꼭질 6 (1) | 2022.12.09 |
[백준 15657번] 파이썬 - N과 M(8) (0) | 2022.11.09 |