Make me a minimum magic sum

Python 2, 44 bytes

a,b,c,d=sorted(input())
print min(c-a,d-b)*2

Try it online!

Sorts the input as a,b,c,d, in ascending order, takes the smaller of c-a and d-b, and doubles it. Why does this work?

First, note that when we change an element to maximize to total cyclic sum of distances, it's optimal (or tied for optimal) to change it to equal a neighbor, such as 17, -6, 15, 33 -> 17, 17, 15, 33. That's because its new total distance to its left and right cyclic neighbors is at least the distance between those neighbors, so making these be equal is the best we can do.

Now, deleting one of two adjacent copies of a number gives the same cyclic sum of distances. In the example, this is 17, 15, 33, giving distances 2 + 18 + 16. So instead of replacing one of the four numbers, it's equivalent to just delete it leaving three numbers, and using the sum of their cyclic distances.

Notice that with 3 numbers, the largest distance is the sum of the two smaller ones. This is because if we sort the numbers to have a ≤ b ≤ c, then |a - c| = |a - b| + |b - c|. In other words, we travel between the largest and smallest number twice, using the medium number as a pit stop one of the times. So, the sum of the three distances is just twice the distance between the minimum and maximum, so (c-a)*2.

So, the question is which number we delete to get the smallest distance between the minimum and maximum of the three numbers that remains. Clearly we delete either the smallest or the largest of the numbers. Calling them a, b, c, d in sorted order, deleting a leaves d - b, and deleting d leaves c - a, and the final result is double whichever is smaller.


Jelly, 6 bytes

ṢŒœIṂḤ

Try it online!

A port of my Python answer.

     (input)        [17, -6, 15, 33]
Ṣ    sort           [-6, 15, 17, 33]
Œœ   odd-even elts  [[-6, 17], [15, 33]]
I    increments     [23, 18]
M    minimum        18
Ḥ    double         36 

R, 66 33 bytes

function(x)2*min(diff(sort(x),2))

Try it online!

Much shorter with xnor's algorithm (go read their explanation and upvote their post!).

Old version:

R, 66 bytes

function(x,m=matrix(x,3,4))min(colSums(abs(diff(rbind(m,m[1,])))))

Try it online!

Takes input as a vector of 4 integers.

This works because the minimum can be attained by setting one of the numbers as equal to one of its neighbours (it is not the only way of attaining the minimum). To see why this is true, find a configuration which achieves the minimum; say we have changed \$p_2\$. Any value of \$p_2\$ such that \$p_1\leq p_2\leq p_3\$ will give the same sum (\$|p_1-p_2|+|p_2-p_3|\$ remains constant), so we can choose \$p_2=p_1\$.

There are 4 ways of choosing which number we change; for each of these, we only have to compute the sum of 3 absolute differences.

The code sets the values in a \$3\times4\$ matrix, where each column represents a subset of size 3 of the 4 numbers. Copy the first row to a 4th row with rbind and compute the absolute differences, then take the minimum of the column sums.