Tối đa hóa sự khác biệt bình phương


19

Xem xét một hoán vị của các giá trị nguyên từ 1đến N. Ví dụ: ví dụ này cho N = 4:

[1, 3, 4, 2]

Chúng tôi sẽ xem danh sách này là tuần hoàn, như vậy 12được coi là liền kề. Một đại lượng chúng ta có thể tính toán cho một danh sách như vậy là tổng chênh lệch bình phương của các giá trị liền kề:

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

Nhiệm vụ của bạn là tìm một hoán vị tối đa hóa đại lượng này, với một số nguyên dương N. Trong trường hợp N = 4ví dụ trên là không tối ưu (trên thực tế, nó là tối thiểu). Chúng ta có thể đạt được sự khác biệt tổng bình phương 18với hoán vị sau (cũng như một số khác):

[1, 4, 2, 3]

Thuật toán của bạn phải chạy trong thời gian đa thức (của N). Cụ thể, bạn không thể đơn giản tính tổng chênh lệch bình phương của tất cả các hoán vị.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Đầu ra có thể ở bất kỳ định dạng thuận tiện, rõ ràng, danh sách phẳng hoặc chuỗi. Bạn có thể chọn để trả về một danh sách với giá trị từ 0để N-1thay vì 1để N.

Luật tiêu chuẩn được áp dụng.

Kiểm tra dữ liệu

Có một giải pháp phân tích tốt cho vấn đề này. Ví dụ: tất cả các giải pháp hợp lệ cho N = 10tương đương với danh sách sau đây (tối đa thay đổi theo chu kỳ và đảo ngược):

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

Tôi không muốn tiết lộ quá nhiều về điều đó (mặc dù có thể đủ để tìm ra mô hình), vì vậy thay vì đưa ra bất kỳ ví dụ nào khác, bạn có thể kiểm tra xem kết quả của bạn có tổng số khác biệt bình phương nào sau đây không 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

Đây là mục AE484842 của OEIS (cũng chứa tài liệu tham khảo cho một bài viết với giải pháp cho thách thức này nếu bạn bị mắc kẹt).

Câu trả lời:


7

Thạch, 24 21 15 14 10 9 byte

RUĖµ«/€ị"

Để tính tổng chênh lệch bình phương, hãy thêm µ_ṙ1$²Svào mã. Hãy thử trực tuyến!

Lý lịch

Một cách để tạo ra một hoán vị với sự khác biệt bình phương tối đa là lấy các số nguyên từ 1 đến n theo thứ tự tăng dần và hoán đổi thứ hai từ bên trái với thứ hai từ bên phải, thứ tư từ bên trái với thứ tư từ bên phải, và vì vậy cho đến khi chúng ta gặp nhau ở giữa

Ví dụ: với n = 8, 9 chúng ta có

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

(dấu mũ số nguyên được hoán đổi), kết quả là

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

sau khi hoán đổi.

Một cách để đạt được các giao dịch hoán đổi này, độc lập với tính chẵn lẻ của n , như sau.

Bắt đầu bằng cách viết các số nguyên theo thứ tự tăng dần và theo thứ tự giảm dần, cái này nằm dưới cái kia.

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

Đối với mỗi cặp số nguyên, hãy tính tối thiểu của cặp. Điều này cho khoảng cách đến cạnh gần nhất, nghĩa là chỉ số từ bên trái hoặc bên phải (tùy theo mức nào thấp hơ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

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

Nếu mức tối thiểu là số lẻ, số nguyên sẽ giữ nguyên vị trí của nó, vì vậy chúng tôi chọn số nguyên từ hàng đầu tiên; nếu là số chẵn, số nguyên sẽ được hoán đổi, vì vậy chúng tôi chọn một số từ hàng thứ hai.

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

Đây là đầu ra mong muốn.

Làm thế nào nó hoạt động

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 byte

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

9 byte được lưu nhờ @Neil!

Giải trình

Cách tiếp cận này xác định số nên ở chỉ mục ivới độ dài nthay vì nối các kết quả thành một mảng. Điều này dựa trên quan sát sau đây (sử dụng n = 7làm ví dụ):

  • Bắt đầu với số thấp nhất bên trái và cao nhất bên phải: [ 1, 7 ]
  • Chuyển thứ tự sao cho thấp nhất ở bên phải và cao nhất ở bên trái, tăng thấp nhất, giảm cao nhất và đặt chúng ở giữa mảng:[ 1, 6, 2, 7 ]
  • Lặp lại cho đến khi hội tụ cao nhất và thấp nhất: [ 1, 6, 3, 4, 5, 2, 7 ]

Những con số cao hơn và thấp hơn có thể dễ dàng được thể hiện dưới dạng n-ii+1tương ứng.

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>


Thuật toán đẹp; Tôi đã thử và thất bại khi nghĩ ra một công thức để tạo ra chúng vì vậy tôi đã phải sử dụng phương pháp đẩy và không di chuyển xấu hơn. Tuy nhiên, tất nhiên tôi có thể đơn giản hóa logic của bạn (i<n/2||n%2)^i%2?i+1:n-i.
Neil

@Neil Wow, tôi vừa thức dậy, quyết định đánh golf này và đưa ra logic chính xác của bạn và bắt đầu gõ nó ngay khi bạn đăng nó! Điên rồ ...
user81655

5

Python2, 105 98 byte

7 byte được lưu nhờ nhận xét của @Dennis

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

Đã chỉnh sửa phiên bản 58 byte

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

Tôi đã tin rằng nó có thể làm điều đó như một lớp lót, nhưng logic quá phức tạp đối với tôi. Thấy câu trả lời JavaScript của @ user81655 và ký hiệu lambda trong @Dennis Python-answer, tôi đã thử nó mới.

Điều kiện bằng

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

Thật không may, tất cả các nỗ lực chuyển đổi chỉ tiết kiệm được một byte so với bản dịch trực tiếp (i<n/2or n%2)!=i%2của logic JavaScript.


3
Chào mừng bạn đến với Câu đố lập trình & Code Golf! Đây có vẻ là Python 2, vì vậy bạn không cần int()xung quanh đầu vào. Ngoài ra, bạn có thể đặt cơ thể của vòng lặp trên cùng một dòng với for....
Dennis

4

Python, 51 49 byte

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

Cảm ơn @xnor vì đã chơi golf 2 byte!

Hãy thử nó trên Ideone .

Làm thế nào nó hoạt động

Nếu i là một số trong [0, ..., n - 1] , thì ~ i% n = - (i + 1)% n = - (i + 1) + n = (n - 1) - i , nghĩa là nó ánh xạ 0 đến n - 1 , 1 đến n - 2 và nói chung, mục thứ j từ bên trái sang thứ j từ bên phải.

Như đã giải thích trong câu trả lời Jelly của tôi , chúng ta có thể xây dựng đầu ra bằng cách nhìn trộm ở giá trị thấp hơn giữa i~ i% n , và chọn i nếu nó là số chẵn và ~ i% n nếu là số lẻ. Chúng tôi đạt được điều này như sau.

  • Nếu mức tối thiểu là chẵn, min(i,~i%n)%-2sẽ mang lại 0 , vì vậy XOR kết quả với i sẽ mang lại i và tính toán dư lượng modulo n sẽ trả về i .

  • Nếu mức tối thiểu là số lẻ, min(i,~i%n)%-2sẽ mang lại -1 , do đó, XOR kết quả với i sẽ mang lại ~ i , do đó toàn bộ biểu thức ước tính ~ i% n như mong muốn.


Bạn có thể lưu một vài ký tự bằng cách làm điều kiện như (i^min(i,n+~i)%-2)%n.
xnor

Điều đó không chỉ ngắn mà còn rất thông minh. Cảm ơn bạn!
Dennis

2

PHP, 77 76 51 50 49 byte

Sử dụng mã hóa ISO 8859-1.

Lắp ráp nửa đầu của mảng như thế này:

  • Các số lẻ có giá trị chỉ mục của chúng (1, 3, 5 ..)
  • Các số chẵn có giá trị là N+1-index(9, 7, 5)
  • Kết quả này trong 1, 9, 3, 7, 5

Đối với nửa sau của mảng, các giá trị ngoài cùng cộng vào N+1, có nghĩa là bạn có thể nhận được giá trị bên phải tương ứng từ N-[left value]nơi giá trị bên trái đã được biết.

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

Chạy như thế này (điều này cũng cho thấy sự khác biệt tổng bình phương) (chỉ -dđược thêm vào cho tính thẩm mỹ):

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
  • Đã lưu một byte bằng cách phủ định điều kiện trái / phải để ternary thứ hai có thể được lồng mà không có dấu ngoặc đơn
  • Đã lưu 25 byte bằng cách thực hiện thuật toán của Dennis một cách đáng xấu hổ
  • Đã lưu một byte bằng cách loại bỏ không gian cần thiết sau echo
  • Đã lưu một byte bằng cách sử dụng để mang lại một khoảng trắng.

1

Con trăn 2, 100

Tôi biết đã có một câu trả lời trăn, nhưng tôi nghĩ rằng tôi có thể đã làm điều này khác đi.

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

Và như một phần bổ sung để kiểm tra tổng số điểm:

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))sử dụng gói ẩn xung quanh các chỉ số âm và lưu 4 byte. Tôi biết, không phải là một phần của cuộc thi. ;)
btwlf

1

CJam, 17 15 14 byte

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

Đây là một hàm bật một số nguyên n từ ngăn xếp và trả lại một hoán vị [0 N n-1] . Mã sử ​​dụng cách tiếp cận tương tự như câu trả lời Jelly của tôi .

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

,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 byte

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

Các đầu vào của hàm cho phép chọn các giá trị start (m) và end (n) của chuỗi.

Để kiểm tra chức năng theo các mẫu được cung cấp, n được cố định là N và m thành 1.

Đây là mã để kiểm tra chức năng:

    (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))

Hãy thử nó trên Ideone !


1

Julia, 39 byte

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

Điều này in một hoán vị 1: n . Hoán vị 0: n-1 không tốn chi phí cũng không tiết kiệm byte:

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

Phiên bản cuối cùng này là một cổng trực tiếp của câu trả lời Python của tôi .


0

ES6, 77 byte

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

Các i&1mẫu chữ số từ cực trị đến giữa. Việc i&2thêm chúng vào đầu hoặc cuối kết quả theo cặp.


0

R, 117 86 byte

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

chỉnh sửa thay thế phiên bản dài bị lỗi bằng cách triển khai thuật toán @Dennis 'Jelly

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.