모든 좌표까지 맨해튼 거리 합이 최소가 되는 위치를 구하는 방법

1. 모든 점까지 맨해튼 거리의 합이 최소가 되는 점의 위치?

 

m차원의 n개의 점들 P1(x11,x12,...,x1m),...Pn(xn1,xn2,...,xnm)에 대하여,

 

이들까지 맨해튼 거리의 합이 최소가 되는 점 X의 좌표를 구하라고 한다면, 어떻게 구할 수 있을까?

 

정답은 n개의 점들을 1,2,...,m차원의 좌표 값에 대하여 정렬한 다음, 중앙값에 해당하는 점의 좌표 Pmedian이 된다.

 

직관적으로 쉽게 눈치챌 수 있기는 한데, 왜 그런지 생각해보자.

 

 

2. 증명

 

먼저 점들의 좌표가 합에 서로 영향을 주지 않는다는 점을 관찰하자.

 

예를 들어 (3,5), (4,2), (5,1)에 대하여 (x,y)까지 맨해튼 거리의 합은..

 

|x3|+|y5|+|x4|+|y2|+|x5|+|y1|=|x3|+|x4|+|x5|+|y5|+|y2|+|y1|

 

즉 맨해튼 거리의 합은 각 차원의 좌표 합끼리 나눌 수 있다.

 

(x1,y1),(x2,y2),...,(xn,yn)에 대하여..

 

S=ni=1|xxi|+ni=1|yyi|

 

그러므로 하나의 차원에 대해 최솟값을 생각한다면, 나머지 차원에 대해서도 동일하게 생각할 수 있다.

 

즉, 이제 문제는 f(x)=ni=1|xxi|가 최소가 되는 x는 무엇인가?

 

 

마찬가지로 합이 서로 영향을 주지 않기 때문에 일반성을 잃지 않고 x1<x2<...<xn으로 정렬된 상태를 가정할 수 있다.

 

정렬한 상태에서 어떤 m에 대하여, xmx<xm+1이 성립하는 x에 대하여...

 

x1,x2,x3,...,xm는 x보다 작거나 같으므로 |xxi|=xxi

 

xm+1,xm+2,...,xn은 x보다 크므로, |xxi|=xix

 

그러므로, f(x)=mi=1(xxi)+ni=m+1(xix)

 

식을 계산해보면... f(x)=mx(nxmx)+ni=m+1ximi=1xi=(2mn)x+ni=m+1ximi=1xi

 

x에 대해 미분하면, f'(x) = 2m-n이다.

 

그러므로, f'(x) > 0인 2m > n이면 f(x)가 증가하고 f'(x) < 0인 2m < n이면 f(x)가 감소하고 n = 2m에서 극값을 가진다.

 

이 말이 무슨말일까?

 

m < n/2이면, f(x)가 감소하다가 m = n/2에서 극값을 가지고 m > n/2이면 f(x)가 증가하는 형태이다.

 

즉, m = n/2에서 f(x)가 최솟값을 가진다. 

 

구체적으로 n = 2m-1이라고 하자. 

 

n = 1 >>> m = 1

 

n = 3 >>> m = 2

 

n = 5 >>> m = 3

 

n = 7 >>> m = 4

 

...

 

예를 들어 n = 7인 경우 n/2 = 3.5인데, m으로 3.5보다 작은 값 m = 3을 고른다면, x3x<x4인 x에 대해서는 f(x)가 감소한다.

 

하지만 m > 3.5보다 큰 m = 4를 고르면 x4x<x5의 x에 대해서는 f(x)가 증가한다.

 

그러므로 x=x4에서 f(x)가 최솟값을 가진다고 이해할 수 있다.

 

 

이번엔 n = 2m으로 짝수라고 해보자.

 

n = 2 >> m = 1

 

n = 4 >> m = 2

 

n = 6 >> m = 3

 

n = 8 >> m = 4

 

...

 

예를 들어 n = 8인 경우 n/2 = 4인데, m으로 4보다 작은 값 m = 3에 대하여... x3x<x4인 x에 대해서는 f(x)가 감소한다.

 

그러다가 m = 4를 고르면 x4x<x5인 x에 대해서 f(x)가 0이 된다. 

 

그리고 m = 5를 고르면 x5x<x6인 x에 대해서는 f(x)가 증가하기 시작한다.

 

그러므로 x4x<x5인 모든 x에 대하여 f(x)가 최소가 된다.

 

즉 n = 2m-1로 홀수이면 xm으로 유일한 점이 존재하지만,

 

n = 2m으로 짝수이면 xmx<xm+1인 모든 x에 대해 최소가 될 수 있다.

 

 

 

3. 연습문제1

 

14400번: 편의점 2 (acmicpc.net)

 

14400번: 편의점 2

영선이는 이번에 편의점으로 창업을 하려고 계획 중이다. 이번 창업을 위해 많은 준비를 하고 있는데, 아직 편의점을 세울 위치를 결정을 하지 못했다. 영선이는 미리 시장조사를 하여, 주요 고

www.acmicpc.net

 

 

4. 풀이

 

n이 10만이라 위의 사실을 모르면 단순하게 풀기 어렵다..

 

위 알고리즘에 따라 x,y좌표 각각 x_points, y_points 배열 각각에 좌표들을 모아둔다.

 

x_points, y_points를 모두 정렬한다.

 

그리고 중앙에 있는 좌표 x_points[n//2], y_points[n//2]가 모든 맨해튼 거리의 합을 최소로 하는 점의 좌표이므로 이를 구한다.

 

x_points,y_points를 다시 순회하여 x_points[n//2], y_points[n//2]의 맨해튼 거리의 합을 구한다.

 

from sys import stdin

n = int(stdin.readline())

x_points = []
y_points = []

for _ in range(n):
    
    x,y = map(int,stdin.readline().split())

    x_points.append(x)
    y_points.append(y)

x_points.sort()
y_points.sort()

x,y = x_points[n//2],y_points[n//2]

answer = 0

for i in range(n):

    answer += abs(x_points[i] - x)
    answer += abs(y_points[i] - y)    

print(answer)

 

 

증명하다가 느낀게 n = 7이면 7//2 = 3인데... 위에서 보인거라면 x4에서 최소여야하는데??

 

라고 생각했는데...

 

배열은 제로 인덱스라서 x_points[3]이 x4잖어..

 

 

 

5. 연습문제2

 

27297번: 맨해튼에서의 모임 (acmicpc.net)

 

27297번: 맨해튼에서의 모임

첫 번째 줄에 점의 차원을 나타내는 정수 N과 점의 개수를 나타내는 정수 M (1N,M1000)이 공백으로 구분되어 주어진다. 다음 M개의 줄에는 i번째 점의 좌표 $P_i = (P_{i,1}, P_{i,2}, \cdots,

www.acmicpc.net

 

정답이 여러개일 경우 아무거나 하나만 출력하라고 나와있는데 위에서 보인대로,

 

점의 개수가 짝수일 경우 중앙의 점 xm, xm+1로 이은 선분 위의 모든 점 xmx<xm+1에 대해 답이 될 수 있기 때문이다.

 

 

 

6. 풀이

 

위의 문제는 2차원이지만 이번 문제는 n차원에서 모든 맨해튼 거리의 합이 최소가 되는 점의 좌표를 구하는 것이다.

 

마찬가지로 동일하게 각 차원마다 좌표 배열 points[0], points[1], ... , points[n-1]을 모두 모아둔다.

 

points를 순회해서 얻은 points[0], points[1],..., points[n-1]에 대하여...

 

points[i] = point라 하고 이들을 정렬한다.

 

point에는 m개의 점 좌표가 들어있으므로 중앙의 좌표는 point[m//2]이다.

 

실제 최소가 되는 점의 좌표를 구해야하므로 point[m//2]도 따로 저장해두고, 다시 point를 하나하나 순회해서 

 

맨해튼 거리 합을 누적시켜준다.

 

from sys import stdin

n,m = map(int,stdin.readline().split())

points = [[] for _ in range(n)]

for _ in range(m):
    
    p = list(map(int,stdin.readline().split()))

    for i in range(n):
        
        points[i].append(p[i])

fermat = []

answer = 0

for point in points:
    
    point.sort()

    fermat.append(point[m//2])

    for p in point:
        
        answer += abs(p - fermat[-1])

print(answer)
print(' '.join(map(str,fermat)))
728x90