การเรียงสับเปลี่ยนในการปลอมตัว


17

กำหนดnเวกเตอร์มิติvกับรายการจริงพบการเปลี่ยนแปลงที่อยู่ใกล้pของ(1,2,...,n)ด้วยความเคารพต่อl1 -distance

รายละเอียด

  • ถ้ามันเป็นความสะดวกสบายมากขึ้นคุณสามารถใช้พีชคณิต(0,1,...,n1)แทน หากมีการเรียงสับเปลี่ยนที่ใกล้เคียงที่สุดคุณสามารถส่งออกหนึ่งรายการหรือทั้งหมดก็ได้
  • l1ระยะห่างระหว่างสองเวกเตอร์u,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]

อ็อกเทฟสคริปต์สำหรับสร้างตัวอย่างเพิ่มเติม


เรารับประกันได้หรือไม่ว่าองค์ประกอบทั้งหมดของvจะมากกว่า0หรือไม่ หรืออย่างน้อยก็ไม่0?
Shaggy

1
ไม่รายการของvสามารถเป็นจำนวนเต็มใด ๆ ได้ (เพิ่มตัวอย่างเพิ่มเติม)
flawr

หากพวกเขาสามารถเป็นตัวเลขจริงใด ๆ แล้ว[1.6 2]เป็นกรณีทดสอบที่สำคัญ (อัลกอริทึมโลภ / เรียงลำดับพจนานุกรมให้คำตอบที่ผิด)
ประวัติศาสตร์ 24

2
ทำซ้ำในการปลอมตัว? ฉันไม่แน่ใจว่าควรปิดเช่นนี้เพราะไม่ชัดเจนว่าเป็นงานเดียวกัน (ตามที่ได้รับการพิสูจน์โดย xnor)
Arnauld

1
(อันที่จริงแล้วมันไม่ใช่งานเดียวกัน แต่ทางออกทั้งหมดของความท้าทายที่เชื่อมโยงกันคือคำตอบของเรื่องนี้)
Arnauld

คำตอบ:


13

Python 2 , 60 ไบต์

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

ลองออนไลน์!

ใช้การจัดทำดัชนีเป็นศูนย์

อัลกอริทึมที่รวดเร็วพร้อมแนวคิดง่ายๆ ถ้าเราแทนต้องเปลี่ยนรูปรายการป้อนข้อมูลที่จะทำให้มันใกล้เคียงกับ(1,2,...,n)ที่เป็นไปได้เราควรจะเป็นเพียงแค่การจัดเรียงมันพิสูจน์แล้วว่าเป็นด้านล่าง เนื่องจากเรากำลังแทน permuting (1,2,...,n)เราเลือกการเปลี่ยนแปลงที่สั่งแบบเดียวกับรายการการป้อนข้อมูลที่เหมือนในความท้าทายของฉันเลียนแบบสั่ง (ยกเว้นการป้อนข้อมูลที่อาจจะมีซ้ำ) (แก้ไข: ไมล์ชี้ให้เห็นความท้าทายที่เหมือนกันนี้ซึ่งเดนนิสมีคำตอบเดียวกันนี้)

การอ้างสิทธิ์:การเปลี่ยนแปลงของรายการlที่ช่วยลดระยะทางในการ(1,2,...,n)เป็นlเรียง

พิสูจน์:พิจารณาบางส่วนการเปลี่ยนแปลงอื่น ๆlของลิตรlเราจะพิสูจน์ว่ามันไม่ดีไปกว่าการจัดเรียง l

เลือกสองดัชนีi,jที่lมีออกจากคำสั่งซื้อที่เป็นที่i<jแต่ li>lj J เราแสดงให้เห็นว่าการแลกเปลี่ยนพวกเขาไม่สามารถเพิ่มระยะทางในการ(1,2,...,n) ) เราทราบว่าการแลกเปลี่ยนเปลี่ยนผลงานทั้งสององค์ประกอบดังต่อไปนี้:

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

Here's a neat way to show this can't be an increase. Consider two people walking on a number line, one going from li to i and the other from lj to j. The total distance they walk is the expression on the left. Since i<j but li>lj, they switch who is higher on the number line, which means they must cross at some point during their walks, call it p. But when they reach p, they could then swap their destinations and walk the same total distance. And then, it can't be worse for them to have walked to their swapped destinations from the start rather than using p as a waypoint, which gives the total distance on the right-hand side.

So, sorting two out-of-order elements in l makes its distance to (1,2,...,n) smaller or the same. Repeating this process will sort l eventually. So, l sorted is at least as good as l for any choice of l, which means it as optimal or tied for optimal.

Note that the only property of (1,2,...,n) that we used is that it's sorted, so the same algorithm would work to permute any given list to minimize its distance to any fixed list.

In the code, the only purpose of z=zip(l,range(len(l))) is to make the input elements distinct, that is to avoid ties, while keeping the same comparisons between unequal elements. If the input we guaranteed to have no repeats, we could remove this and just have lambda l:map(sorted(l).index,l).


brilliant insight
Jonah

You've simplified this into finding the ordering.
miles

@miles That's pretty funny, I completely forgot about that challenge even though I wrote an answer, and Dennis has this exact Python answer which I helped golf.
xnor

That "visual proof" is neat. I got the same idea but had to lay out each case of that formula to prove it. As a side remark, a few alternatives of obtaining ranks in Python using third-party libraries are shown in this post.
Joel

5

05AB1E, 7 bytes

āœΣαO}н

Try it online!


Explanation

ā              # 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
Everytime i'm amazed by this, what 05AB1E can't do ?
The random guy

5
@Therandomguy There aren't a lot of things which cannot be done in 05AB1E, but it's pretty bad at: regex-based challenges; matrix-based challenges (although this has been improved after some new builtins); lack of imaginary numbers; date/time related challenges; etc. However, although hard, it can still be done usually. To give two examples: The Work Day Countdown (go to next day, and get day of week are done manually); Quine outputs itself in binary (UTF-8 conversion is done manually).
Kevin Cruijssen

@Grimy should be fixed now :)
Expired Data

3

Perl 6, 44 bytes

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

Try it online!

Anonymous codeblock that returns the first minimum permutation with 0 indexing.

Explanation:

{                                          }   # 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

I think I might also be able to get rid of the .sum and sort by just the list of absolute values, but I'm not sure this is actually corret, though it passes my current test cases.


1
That was breaking my brain too (or the mostly-equivalent question of "does a greedy algorithm work for this?"). The simplest counterexample is [0.6 1] (assuming we're 0-indexed), where if you optimize for the first value you get [1,0] for a score of 1.4, but if you optimize for the whole vector the 1 is more valuable in the second position for a score of 0.6.
histocrat


2

Jelly, 5 bytes

Œ¿œ?J

A monadic Link accepting a list of numbers which yields a list of integers.

Try it online! Or see the test-suite.

How?

Œ¿œ?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

N.B. L (length of) would work in place of J since œ? given an integer, n, on the right would implicitly make the range [1..n] to work with, but J is explicit.


2

Ruby, 63 60 bytes

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

Try it online!

There's a math trick here that could be helpful in other answers too--instead of minimizing the sum of the absolute values of the differences, we maximize the sum of the products. Why does that work?

Minimizing the sum of (x-y) squared isn't equivalent to minimizing the sum of |x-y|, but it will always give a valid answer, it just prioritizes reducing large differences over small ones whereas the actual challenge is indifferent between the two.

But (x-y)*(x-y) = x*x+y*y-2*x*y. Since the square terms will always show up somewhere in the sum for any permutation, they don't affect the result, so we can simplify to -2*x*y. The 2 factors out, so we can simplify to -x*y. Then if we change minimizing to maximizing, we can simplify to x*y.

Intuitively, this is similar to observing that if you're trying to maximize square footage using a set of horizontal walls and a set of vertical ones, you're best off pairing walls that are close in size to each other to create rooms that are as close to square as possible. 3*3 + 4*4 = 25, while 3*4 + 4*3 = 24.

Edit: Saved three bytes by generating and evaluating a format string instead of using zip and sum.


2
Minimizing the sum of (x-y) squared isn't equivalent to minimizing the sum of |x-y|, but it will always give a valid answer. Why is it the case? Is there no y that minimizes |xy| but not (xy)2?
Joel

1

Gaia, 13 bytes

e:l┅f⟪D†Σ⟫∫ₔ(

Try it online!

e:		| eval and dup input
l┅f		| push permutations of [1..length(input)]
⟪   ⟫∫ₔ		| iterate over the permutations, sorting with minimum first
 D†Σ		| the sum of the absolute difference of the paired elements
       (	| and select the first (minimum)

1

JavaScript (ES6), 61 bytes

Based on xnor's insight.

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

Try it online!

Commented

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 bytes

There  must be  definitely is a more direct way...

0-indexed.

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

Try it online! (with 1-indexed output)

How?

The helper function g computes all permutations of (0,...,n1), where n is the implicit length of the input array a[].

For each permutation p, we compute:

k=n1+i=0n1(piai)2
The only reason for the leading n1 is that we re-use the internal counter of g to save a few bytes, but it has no impact on the final result.

We eventually return the permutation that leads to the smallest k.



1

Python 2, 149 126 112 bytes

-23 bytes thanks to Mr. Xcoder

-14 bytes thanks to 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)))

Try it online!

Uses permutations of (0 ... n-1).


You can switch to Python 2, so that you don't need functools anymore.
Mr. Xcoder

reduce is usually overkill, especially here where you're adding stuff. I think you can just do sum(abs(p-q)for p,q in zip(x,a)).
xnor

0

w/o any permutation package

Python 3, 238 bytes

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]

Try it online!



0

Japt -g, 12 bytes

Êõ á ñÈíaU x

Try it

For 0-indexed, replace the first 2 bytes with m, to map the array to its indices instead.

Êõ á ñÈí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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.