Перестановки в маскуванні


17

З огляду на n - мірний вектор v з речовими елементами, знайти найближчу перестановку з по відношенню до -відстані.p(1,2,...,n)l1

Деталі

  • Якщо це зручніше, ви можете використовувати перестановки замість цього. Якщо є декілька найближчих перестановок, ви можете вивести будь-яку або альтернативно всі з них.(0,1,...,n1)
  • Відстань між двома векторами визначається якl1u,v
    d(u,v)=i|uivi|.
  • Якщо ви хочете, ви можете припустити, що вхід складається виключно з цілих чисел.

Приклади

[0.5  1] -> [1 2], [2 1]
c*[1 1 ... 1] -> any permutation
[1 4 2 6 2] -> [1 4 3 5 2], [1 4 2 5 3]
[1 3 5 4 1] -> [2 3 5 4 1], [1 3 5 4 2]
[7 7 3 2 5 6 4 2] -> [8 7 3 2 5 6 4 1], [8 7 3 1 5 6 4 2], [7 8 3 2 5 6 4 1], [7 8 3 1 5 6 4 2]
[-2 4 5 7 -1 9 3] -> [1 4 5 6 2 7 3], [2 4 5 6 1 7 3], [1 4 5 7 2 6 3], [2 4 5 7 1 6 3]
[0 4 2 10 -1 10 5] -> [1 4 2 6 3 7 5], [1 4 3 6 2 7 5], [2 4 3 6 1 7 5], [3 4 2 6 1 7 5], [1 4 2 7 3 6 5], [1 4 3 7 2 6 5], [2 4 3 7 1 6 5], [3 4 2 7 1 6 5]

Сценарій Octave для створення більше прикладів.


Ми гарантуємо, що всіх елементів v, буде більше, ніж 0? Або, принаймні, ні 0?
Кошлатий

1
Ні, записи vможуть бути будь-якими цілими числами. (Додано ще кілька прикладів.)
недолік

Якщо вони можуть бути будь-якими реальними числами, то [1.6 2]це важливий тестовий випадок (жадібний алгоритм / лексикографічний сорт дає неправильну відповідь).
гістократ

2
Дублікат у маскуванні? Я не впевнений, що це має бути закрите як таке, оскільки не очевидно, що це те саме завдання (як зараз довів xnor).
Арнольд

1
(Насправді це не одне і те ж завдання, але всі рішення пов'язаного виклику - це рішення цього.)
Арнольд,

Відповіді:


13

Python 2 , 60 байт

def f(l):z=zip(l,range(len(l)));print map(sorted(z).index,z)

Спробуйте в Інтернеті!

Використовує нульову індексацію.

Швидкий алгоритм з простою ідеєю. Якщо замість цього ми повинні переставити список введення , щоб зробити його як можна ближче до (1,2,...,n) , наскільки це можливо, ми повинні просто розбирайтеся, як доведено нижче. Оскільки ми замість перестановки (1,2,...,n) , ми вибираємо перестановку , що замовили точно так же , як список введення, як в моєму виклику Наслідувати впорядкованість ( за винятком введення може бути повтори). (Редагувати: милі вказали на цю більш ідентичну проблему , де Денніс має таку саму відповідь .)

Затвердження: Перестановка зі списку l , що зводить до мінімуму її відстань до (1,2,...,n) є l відсортований.

Доведення: Розглянемо деякі інші перестановки l з l . Ми доведемо, що це не може бути краще, ніж l відсортований.

Виберіть два індекси i,j які l є поза порядком, тобто i<j але li>lj . Показано , що заміна їх не може збільшити відстань до (1,2,...,n) . Відзначимо, що своп змінює внесок цих двох елементів так:

|lii|+|ljj||lij|+|lji|.

Ось акуратний спосіб показати, що це не може бути збільшенням. Розглянемо двох людей, що йдуть по лінійці чисел, одна переходить від li до i а друга від lj до j . Загальна відстань, яку вони проходять - це вираз зліва. Оскільки i<j але li>lj , вони перемикають того, хто вище на рядку числа, а це означає, що вони повинні перейти в якийсь момент під час своїх прогулянок, називаючи це p . Але коли вони доходять до p, вони можуть змінити місця призначення та пройти ту саму загальну відстань. І тоді, для них не може бути гірше, що вони пішли до своїх міняних місць призначення з самого початку, а не використовувати p в якості маршрутної точки, яка дає загальну відстань в правій частині.

Так, сортування два поза потоком порядку елементів в l робить її відстань до (1,2,...,n) менше або ж. Повторення цього процесу врешті-решт сортуватиме l . Отже, l відсортований як мінімум такий же хороший, як l для будь-якого вибору l , що означає, що він є оптимальним або прив'язаним до оптимального.

Зверніть увагу , що єдине властивість (1,2,...,n) , який ми використовували в тому , що це сортується, так само алгоритм буде працювати переставляти будь-який даний список , щоб мінімізувати її відстань до будь-якого фіксованого списку.

У коді єдина мета z=zip(l,range(len(l)))- зробити вхідні елементи різними, тобто уникнути зв’язків, зберігаючи однакові порівняння між нерівними елементами. Якщо введення, яке ми гарантували, не матиме повторів, ми можемо це видалити і просто мати lambda l:map(sorted(l).index,l).


блискуче прозріння
Йона

Ви спростили це до пошуку замовлення .
миль

@miles Це дуже смішно, я повністю забув про це завдання, навіть коли написав відповідь, і Денніс має таку точну відповідь Python, на яку я допоміг гольфу.
xnor

Це "візуальний доказ" акуратний. Я мав таку саму ідею, але мусив викласти кожен випадок цієї формули, щоб довести це. В якості побічного зауваження в цій публікації показано кілька альтернатив отримання рангів у Python за допомогою сторонніх бібліотек .
Джоель

5

05AB1E , 7 байт

āœΣαO}н

Спробуйте в Інтернеті!


Пояснення

ā              # get the numbers 1 to len(input) + 1
 œ             # Permutations of this
  Σ  }         # Sort by ...
   α           # Absolute difference
    O          # Sum these
      н        # And get the first one 
               # implicitly print

1
Щоразу мене дивує це, що 05AB1E не можу зробити?
Випадковий хлопець

5
@Therandomguy Не так багато речей, які неможливо зробити в 05AB1E, але це дуже погано: виклики на основі регулярних виразів; виклики на основі матриці (хоча це було вдосконалено після деяких нових побудов); відсутність уявних чисел; проблеми, пов'язані з датою / часом; і т. д. Однак, хоч і важко, це все одно можна зробити зазвичай. Навести два приклади: Зворотний відлік робочого дня (перейдіть до наступного дня та отримайте день тижня виконуються вручну); Quine виводить себе у двійковій формі (перетворення UTF-8 здійснюється вручну).
Kevin Cruijssen

@Grimy слід виправити зараз :)
Термін дії даних закінчився

3

Perl 6 , 44 байти

{permutations(+$_).min((*[]Z-$_)>>.abs.sum)}

Спробуйте в Інтернеті!

Анонімний кодовий блок, який повертає першу мінімальну перестановку з 0 індексуванням.

Пояснення:

{                                          }   # Anonymous code block
 permutations(+$_)                             # From the permutations with the same length
                  .min(                   )    # Find the minimum by
                                      .sum       # The sum of
                                >>.abs           # The absolute values of
                       (*[]Z-$_)                 # The zip subtraction with the input

Я думаю, що я міг би також позбутися .sumі сортувати лише за списком абсолютних значень, але я не впевнений, що це насправді коррект, хоча він проходить мої поточні тестові випадки.


1
Це теж розбивало мій мозок (або здебільшого еквівалентне питання "чи спрацьовує жаден алгоритм для цього?"). Найпростіший контрприклад - це [0.6 1](якщо припустимо, що ми з індексом 0), де, якщо оптимізувати перше значення, ви отримуєте [1,0]бал 1,4, але якщо ви оптимізуєте для всього вектора, 1 є більш цінним у другій позиції для оцінки 0,6.
гістократ


2

Желе , 5 байт

Œ¿œ?J

Монадічна Посилання, що приймає список чисел, який дає список цілих чисел.

Спробуйте в Інтернеті! Або подивіться тестовий набір .

Як?

Œ¿œ?J - Link: list of numbers, X
Œ¿    - Index of X in a lexicographically sorted list of
         all permutations of X's items
    J - range of length of X
  œ?  - Permutation at the index given on the left of the
         items given on the right

NB L(довжина) буде працювати на місці , Jтак як œ?дано ціле число, nна правому і не прямо зробити вибір [1..n]для роботи, але Jце явно.


2

Рубі , 63 60 байт

->v{[*1..v.size].permutation.max_by{|p|eval [p,0]*'*%p+'%v}}

Спробуйте в Інтернеті!

Тут є математичний трюк, який може бути корисним і в інших відповідях - замість того, щоб мінімізувати суму абсолютних значень різниць, ми максимізуємо суму продуктів. Чому це працює?

Мінімізація суми (x-y) squaredне еквівалентна мінімізації суми |x-y|, але вона завжди дасть вагому відповідь, вона лише надає пріоритет зменшенню великих різниць у порівнянні з малими, тоді як справжній виклик байдужий між ними.

Але (x-y)*(x-y)= x*x+y*y-2*x*y. Оскільки квадратні умови завжди відображатимуться десь у сумі за будь-яку перестановку, вони не впливають на результат, тому ми можемо спростити це -2*x*y. У 2згладжує, тому ми можемо спростити -x*y. Тоді, якщо ми змінимо мінімізацію до максимізації, ми можемо спростити її x*y.

Інтуїтивно це схоже на спостереження, що якщо ви намагаєтеся збільшити квадратні метри, використовуючи набір горизонтальних стін і набір вертикальних, вам найкраще сполучати стіни, близькі за розміром один до одного, щоб створити кімнати, які якомога ближче до квадрата. 3*3 + 4*4 = 25, поки 3*4 + 4*3 = 24.

Редагування: збережено три байти шляхом генерації та оцінки рядка формату замість використання zip та sum.


2
Мінімізація суми (xy) у квадраті не рівнозначна мінімізації суми | xy |, але вона завжди дасть вагому відповідь. Чому це так? Чи немаєу що мінімізує |х-у| але не (х-у)2?
Джоель


1

JavaScript (ES6), 61 байт

На основі розуміння xnor .

a=>[...a].map(g=n=>g[n]=a.sort((a,b)=>a-b).indexOf(n,g[n])+1)

Спробуйте в Інтернеті!

Прокоментував

a =>                    // a[] = input array
  [...a]                // create a copy of a[] (unsorted)
  .map(g = n =>         // let g be in a object; for each value n in the copy of a[]:
    g[n] =              //   update g[n]:
      a.sort(           //     sort a[] ...
        (a, b) => a - b //       ... in ascending order
      ).indexOf(        //     and find the position
        n,              //       of n in this sorted array,
        g[n]            //       starting at g[n] (interpreted as 0 if undefined)
      ) + 1             //     add 1
  )                     // end of map()

JavaScript (ES6),  130  128 байт

Має  бути,  безумовно, є більш прямий спосіб ...

0-індексований.

a=>(m=g=(k,p=[])=>1/a[k]?(h=i=>i>k||g(k+1,b=[...p],b.splice(i,0,k),h(-~i)))``:p.map((v,i)=>k+=(v-=a[i])*v)|k>m||(R=p,m=k))(0)&&R

Спробуйте в Інтернеті! (з 1-індексованим виходом)

Як?

Функція помічника г обчислює всі перестановки (0,...,н-1), де н - неявна довжина вхідного масиву а[].

Для кожної перестановки p, ми обчислюємо:

к=н-1+i=0н-1(pi-аi)2
Єдина причина ведучих н-1 це те, що ми повторно використовуємо внутрішній лічильник г щоб зберегти кілька байт, але це не впливає на кінцевий результат.

Ми зрештою повертаємо перестановку, яка веде до найменшої к.



1

Python 2 , 149 126 112 байт

-23 байти завдяки містеру Xcoder

-14 байт завдяки xnor

from itertools import*
f=lambda a:min(permutations(range(len(a))),key=lambda x:sum(abs(a-b)for a,b in zip(x,a)))

Спробуйте в Інтернеті!

Використовує перестановки (0 ... n-1).


Ви можете перейти на Python 2, так що вам більше не потрібно functools.
Містер Xcoder

reduceзазвичай є надмірним, особливо тут, де ви додаєте речі. Я думаю, ти можеш просто зробити sum(abs(p-q)for p,q in zip(x,a)).
xnor

0

без будь-якого пакета перестановки

Python 3 , 238 байт

def p(a,r,l):
 if r==[]:l+=[a];return
 for i in range(len(r)):
  p(a+[r[i]],r[:i]+r[i+1:],l)
def m(l):
 s=(float("inf"),0);q=[];p([],list(range(len(l))),q)
 for t in q:D=sum(abs(e-f)for e,f in zip(l,t));s=(D,t)if D<s[0]else s
 return s[1]

Спробуйте в Інтернеті!



0

Japt -g , 12 байт

Êõ á ñÈíaU x

Спробуй це

Для 0-індексованих замініть перші 2 байти на, m,щоб замість цього масив відобразити масив.

Êõ á ñÈíaU x     :Implicit input of array U
Ê                :Length
 õ               :Range [0,Ê]
   á             :Permutations
     ñÈ          :Sort by
       í U       :  Interleave with U
        a        :  Reduce each pair by absolute difference
           x     :  Reduce resulting array by addition
                 :Implicit output of first sub-array

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.