Kare farkını en üst düzeye çıkarın


19

Dan tamsayı değerlerinin bir permütasyon düşünün 1için N. Örneğin bu örnek N = 4:

[1, 3, 4, 2]

Bu listeyi döngüsel olarak değerlendireceğiz, öyle ki 1ve 2bitişik olarak ele alınacaktır . Böyle bir liste için hesaplayabileceğimiz bir miktar, bitişik değerlerin toplam kare farkıdır:

(1-3)² + (3-4)² + (4-2)² + (2-1)² = 10

Göreviniz, pozitif bir tam sayı verildiğinde, bu miktarı en üst düzeye çıkaran bir permütasyon bulmaktır N. N = 4Yukarıdaki örnek durumunda, optimal değildir (aslında, minimaldir). 18Aşağıdaki permütasyon ile (ve diğerleri ile) tam bir kare farkı elde edebiliriz :

[1, 4, 2, 3]

Algoritmanız polinom zamanında (/ N) çalıştırılmalıdır . Özellikle, tüm permütasyonların toplam kare farkını hesaplayamazsınız.

STDIN (veya en yakın alternatif), komut satırı bağımsız değişkeni veya işlev bağımsız değişkeni ile girdi alarak ve sonucu STDOUT (veya en yakın alternatif), işlev dönüş değeri veya işlev (çıkış) parametresi aracılığıyla çıktı alarak bir program veya işlev yazabilirsiniz.

Çıktı herhangi bir uygun, açık, düz liste veya dize biçiminde olabilir. Sen değerlerle listesini döndürür seçebilir 0için N-1yerine 1göre N.

Standart kuralları geçerlidir.

Test verisi

Bu sorun için güzel bir analitik çözüm var. Örneğin, için geçerli tüm çözümler N = 10aşağıdaki listeye eşdeğerdir (döngüsel kaymalara ve geri dönüşe kadar):

[7, 5, 6, 4, 8, 2, 10, 1, 9, 3]

Bunun ötesinde çok fazla açıklamak istemiyorum (muhtemelen deseni bulmak için yeterli olsa da), bu yüzden daha fazla örnek vermek yerine, sonuçlarınızın belirli bir toplam için aşağıdaki toplam kare farklarına sahip olup olmadığını kontrol edebilirsiniz N:

N    Total squared difference

1                         0
2                         2
3                         6
4                        18
5                        36
6                        66
7                       106
8                       162
9                       232
10                      322
33                    11936
100                  333202
333                12308236
1000              333332002

Bu OEIS girişi A064842'dir (ayrıca sıkışmışsanız bu soruna bir çözüm içeren bir kağıda başvuru içerir).

Yanıtlar:


7

Jöle, 24 21 15 14 10 9 bayt

RUĖµ«/€ị"

Toplam kare farkını hesaplamak µ_ṙ1$²Siçin koda ekleyin . Çevrimiçi deneyin!

Arka fon

Maksimize kare fark ile bir permütasyon üretmek için bir yolu tamsayılar almaktır 1 için n artan düzende ve böylece sağdan dördüncü sol ve dördüncü, sağdan ikinci sol taraftan ikinci takas ortada buluşana kadar.

Örneğin, n = 8, 9 için

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
  ^   ^ ^   ^            ^   ^   ^   ^

(satır işaretleri değiştirilecek tam sayıları işaretler);

1 7 3 5 4 6 2 8        1 8 3 6 5 4 7 2 9

takas sonra.

N'nin paritesinden bağımsız olarak bu swaplara ulaşmanın bir yolu aşağıdaki gibidir.

Tamsayıları artan sırada ve azalan sırada, biri diğerinin altına yazarak başlayın.

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

Her tamsayı çifti için, çiftin minimum değerini hesaplayın. Bu, en yakın kenara olan mesafeyi verir, yani soldan veya sağdan indeks (hangisi daha düşükse).

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

1 2 3 4 4 3 2 1        1 2 3 4 5 4 3 2 1

Minimum değer garip ise, tamsayı yerinde kalmalıdır, bu yüzden ilk satırdan birini seçeriz; eğer eşitse, tamsayılar değiştirilmelidir, bu yüzden ikinci satırdan birini seçeriz.

1   3     6   8        1   3   5   7   9
  7   5 4   2            8   6   4   2

Bu istenen çıktıdır.

Nasıl çalışır

RUĖµ«/€ị"    Main link. Input: n

R            Range. Yields [1, ..., n].
 U           Upend. Yields [n, ..., 1].
  Ė          Enumerate. Yields p := [[1, n], [2, n-1], ... [n-1, 2], [n, 1]].

   µ         Begin a new, monadic chain. Argument: p
     /       Reduce...
      €        each pair of p...
    «          by minimum.
        "    For each minimum and the corresponding pair of p:
       ị       Select the element at that index.
            Indices are modular and 1-based in Jelly, so this selects the first
            element if the minimum is odd, and the second one if it is even.

6

JavaScript (ES6), 52 bayt

n=>[...Array(n)].map((_,i)=>(i<n/2|n%2)^i%2?i+1:n-i)

@Neil sayesinde 9 bayt tasarruf edildi!

açıklama

Bu yaklaşım, dizin olmalıdır sayısını belirler ibir uzunluğa sahip nyerine bir dizi sonuçları bitiştirme daha. Bu, aşağıdaki gözlemi temel alır ( n = 7örnek olarak kullanarak ):

  • Soldaki en düşük, sağdaki en yüksek sayı ile başlayın: [ 1, 7 ]
  • Sırayı en düşük sağda ve en yüksek solda olacak şekilde değiştirin, en düşük değeri artırın, en yüksek değeri azaltın ve bunları dizinin ortasına yerleştirin:[ 1, 6, 2, 7 ]
  • En yüksek ve en düşük yakınsamaya kadar tekrarlayın: [ 1, 6, 3, 4, 5, 2, 7 ]

Daha yüksek ve daha düşük sayılar sırasıyla n-ive olarak kolayca ifade edilebilir i+1.

var solution =

n=>
  [...Array(n)] // create an array of length n
  .map((_,i)=>  // set each value of the array at index i
    (i<n/2      // if we're on the left side,
    |n%2)       // or we're on the right and n is odd, even i => lower, odd i => higher
    ^i%2?       // else even i => higher, odd i => lower
    i+1:n-i
  )
N = <input type="number" id="input" oninput="result.textContent=solution(+this.value)" />
<pre id="result"></pre>


Güzel algoritma; Onları üretmek için bir formül düşünmeye çalıştım ve başarısız oldum. Ancak, elbette mantığınızı basitleştirebilirim (i<n/2||n%2)^i%2?i+1:n-i.
Neil

@Neil Wow, yeni uyandım, bunu golf oynamaya karar verdim ve tam mantığınızla geldim ve yayınladığınız gibi yazmaya başladınız! Çılgın ...
user81655

5

Python2, 105 98 bayt

@Dennis tarafından yapılan yorum sayesinde 7 bayt kurtarıldı

n=input()
r=([],[n/2+1])[n%2]
for i in range(n/2,0,-1):k=[n+1-i];r=([i]+r+k,k+r+[i])[i%2]
print r

Düzenlenmiş sürüm 58 bayt

lambda n:[(n-i-1,i)[(i+(n,1)[i<n/2])%2]for i in range(n)]

Zaten tek katmanlı olarak yapılabileceğine inandım, ama mantık benim için çok karmaşıktı. @ User81655 tarafından verilen JavaScript yanıtını ve @Dennis Python-yanıtındaki lambda gösterimini görünce yeni bir deneme yaptım.

Durum eşittir

if i < n/2:
    i%2 != n%2
else:
    (i+1)%2

Ne yazık ki tüm dönüşüm çabası , JavaScript mantığının doğrudan çevirisine kıyasla yalnızca bir bayt tasarruf etmiyor (i<n/2or n%2)!=i%2.


3
Programlama Bulmacaları ve Kod Golf hoş geldiniz! Bu Python 2 gibi görünüyor, bu yüzden int()girişin etrafına ihtiyacınız yok . Ayrıca, for döngüsünün gövdesini ile aynı satıra koyabilirsiniz for....
Dennis

4

Python, 51 49 bayt

lambda n:[(i^min(i,~i%n)%-2)%n for i in range(n)]

2 bayt golf için @xnor sayesinde!

Ideone üzerinde deneyin .

Nasıl çalışır

Eğer I bir sayıdır - [1 0, ..., n] , daha sonra p%, n = -, (i + 1)% N = -, (i + 1) + n = (n - 1) - ı , o eşler, yani 0 ile 1 - n , 1 ile n - 2 , genel olarak, ve, j inci soldan madde j th sağdan.

Açıklandığı gibi benim Jelly cevap , biz arasında daha düşük değerde atmayı tarafından çıkışı oluşturabilirsiniz i ve ~ i% n ve almak i bile olup olmadığını ~ ı% n garip ise. Bunu aşağıdaki gibi başarıyoruz.

  • En az çift ise, min(i,~i%n)%-2verecektir 0 dolayısıyla bu sonuç xoring, i verecektir i , ve tortu, modulo işlem n döner i .

  • En az bir tek sayı ise, min(i,~i%n)%-2verecektir -1 , dolayısıyla bu sonucun xoring i verecektir p için tüm ifade değerlendirir çok ı ~% N arzu edildiği gibi.


Koşullu olarak birkaç karakter kaydedebilirsiniz (i^min(i,n+~i)%-2)%n.
xnor

Bu sadece kısa değil, çılgınca akıllı. Teşekkür ederim!
Dennis

2

PHP, 77 76 51 50 49 bayt

ISO 8859-1 kodlamasını kullanır.

Dizinin ilk yarısını şöyle monte etmek:

  • Tek sayıların dizin değeri vardır (1, 3, 5 ..)
  • Çift sayılar N+1-index(9, 7, 5) değerine sahiptir.
  • Bu sonuç 1, 9, 3, 7, 5

Dizinin ikinci yarısına gelince, en dıştaki değerler toplanır N+1, yani N-[left value]sol değerin zaten bilindiği yerden doğru değeri elde edebilirsiniz .

for(;$k=$argv[1]-$j++;)echo" ",min($j,$k)%2?$j:$k;

Bu şekilde çalıştırın (toplam kare farkını da gösterir) ( -dyalnızca estetik için eklenir):

php -d error_reporting=32757 -r 'for(;$k=$argv[1]-$j++;)echo~ß,$x[]=min($j,$k)%2?$j:$k;  for(;$c=$x[+$i++];)$b+=($c-($x[$i]?:$x[0]))**2;echo"\n$b\n";' 10
  • İkinci üçlünün parantez olmadan yuvalanabilmesi için sol / sağ koşulunu reddederek bir bayt kaydetti
  • Dennis algoritmasını utanmadan uygulayarak 25 bayt tasarruf etti
  • Sonra gerekli alandan kurtularak bayt tasarrufu sağlandı echo
  • Boşluk bırakmak için kullanarak bir bayt kaydetti .

1

Python 2, 100

Zaten bir python cevabı olduğunu biliyorum, ama sanırım bunu farklı yapmış olabilirim.

n=input();a=n%2;b=n/2;x=[b+1,b+a][a:]
for i in range(b+a-1):f=1-i%2*2;x=[x[-1]-f]+x+[x[0]+f]
print x

Ve toplam puanı test etmek için ekstra olarak:

def t(x,n):return sum((x[i]-x[(i+1)%n])**2for i in range(n))

def t(x,n):return sum((x[i]-x[i-1])**2for i in range(n))negatif endekslerin örtülü olarak sarılmasını kullanır ve 4 bayt kaydeder. Biliyorum, yarışmanın bir parçası değildi. ;)
btwlf

1

CJam, 17 15 14 bayt

{,W%ee_::e<.=}

Bu, yığından n tamsayısını açan ve karşılığında [0… n-1] permütasyonunu iten bir fonksiyondur . Kod, Jelly yanıtımla aynı yaklaşımı kullanıyor .

Çevrimiçi deneyin!

Nasıl çalışır

,W%ee_::e<.=    Function body. Stack: N

,               Turn N into [0 ... N-1].
 W%             Reverse to push [N-1 ... 0].
   ee           Enumerate. This pushes [[0 N-1] [1 N-2] ... [N-2 1] [N-1 0]].
     _          Push a copy of the array of pairs.
      ::e<      Reduce each pair by minimum.
          .=    Vectorized selection.
                For the Ith minimum M, select the Mth element of the Ith pair.
                Indices are modular and 0-based in CJam, so this selects the first
                element if the minimum is even, and the second one if it is odd.

1

LISP, 86 bayt

(defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

Fonksiyonun girişleri dizinin başlangıç ​​(m) ve bitiş (n) değerlerinin seçilmesine izin verir.

Fonksiyonu verilen örneklere göre test etmek için n, N'ye ve m ila 1'e sabitlenmiştir.

İşte işlevi test etmek için kod:

    (defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

(defun sq (c)
    (apply #'+ (mapcar #'(lambda(x y) (* (- x y) (- x y))) c (append (cdr c) (list (car c))))))

(format t "N~20TSequence~50TSquared Difference~%")
(mapcar #'(lambda (x)(format t "~S~20T~S~50T~S~%" x (g x 1) (sq (g x 1)))) '(1 2 3 4 5 6 7 8 9 10 33 100 333 1000))

Ideone üzerinde deneyin !


1

Julia, 39 bayt

n->map(i->min(i-1,n-i)%2>0?n-~-i:i,1:n)

Bu 1: n'lik bir permütasyon yazdırır . 0: n-1 permütasyonu ne maliyeti ne de bayt tasarrufu sağlar:

n->map(i->min(i,n+~i)%2>0?i:n+~i,0:n-1)

Bu son sürüm benim Python cevabımın doğrudan bir portu .


0

ES6, 77 bayt

n=>[...Array(n)].map(_=>r[++i&2?"push":"unshift"](i&1?n--:++j),i=j=0,r=[])&&r

i&1Numuneler ortadan aşırı rakam. i&2Çiftler halinde sonucun başına veya sonuna ekler.


0

R, 117 86 bayt

z=1:(n<-scan());a=pmin(z,n:1);for(i in seq(2,,2,n%/%2))z[b]=z[rev(b<-which(a==i,T))];z

düzenlemek @Dennis' Jelly algoritmasının bir uygulama ile adamcağız uzun versiyonu yerini

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.