Tạo nhịp điệu Euclide


8

Bạn có biết rằng thuật toán Euclide có khả năng tạo ra nhịp điệu âm nhạc truyền thống ? Chúng ta sẽ thấy cách thức hoạt động của nó bằng cách mô tả một thuật toán tương tự, nhưng hơi khác với thuật toán trong bài báo.

Chọn một số nguyên dương n, tổng số nhịp và số nguyên dương k, số lượng nhịp được phát ra (ghi chú). Chúng ta có thể nghĩ về nhịp điệu như một chuỗi các nbit, ktrong đó là 1s. Ý tưởng của thuật toán là phân phối các số 1 càng nhiều càng tốt giữa các số 0.

Ví dụ: với n = 8k = 5, chúng tôi bắt đầu với 5 cái và 3 số 0, mỗi số theo thứ tự riêng của nó:

[1] [1] [1] [1] [1] [0] [0] [0]

Tại bất kỳ thời điểm nào, chúng ta sẽ có hai loại trình tự - các loại ở đầu là các chuỗi "cốt lõi" và các loại ở cuối là các chuỗi "còn lại". Ở đây các lõi là [1]s và phần còn lại là [0]s. Miễn là chúng tôi có nhiều hơn một chuỗi còn lại, chúng tôi phân phối chúng trong số các lõi:

[1 0] [1 0] [1 0] [1] [1]

Bây giờ cốt lõi là [1 0]và phần còn lại là [1], và chúng tôi phân phối lại:

[1 0 1] [1 0 1] [1 0]

Bây giờ cốt lõi là [1 0 1]và phần còn lại là [1 0]. Vì chúng tôi chỉ có một chuỗi còn lại, chúng tôi dừng lại và nhận chuỗi

10110110

Đây là những gì nó nghe như, lặp đi lặp lại 4 lần:

Đây là một ví dụ khác, với n = 16k = 6:

[1] [1] [1] [1] [1] [1] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0]
[1 0] [1 0] [1 0] [1 0] [1 0] [1 0] [0] [0] [0] [0]
[1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0] [1 0]
[1 0 0 1 0] [1 0 0 1 0] [1 0 0] [1 0 0]
[1 0 0 1 0 1 0 0] [1 0 0 1 0 1 0 0]
1001010010010100

Lưu ý cách chúng tôi kết thúc ở bước cuối cùng với hai chuỗi cốt lõi và không có chuỗi còn lại. Đây là, lặp lại hai lần:

Đầu vào

Bạn có thể viết một hàm hoặc một chương trình đọc toàn bộ từ STDIN, dòng lệnh hoặc tương tự. Đầu vào sẽ là hai số nguyên dương nk <= n, mà bạn có thể giả sử theo thứ tự.

Đầu ra

Nhiệm vụ của bạn là xuất ra nhịp điệu được tạo dưới dạng một nchuỗi ký tự dài. Bạn có thể chọn bất kỳ hai ký tự ASCII có thể in riêng biệt (0x20 đến 0x7E) để thể hiện các ghi chú và phần còn lại.

Các trường hợp thử nghiệm

Các trường hợp kiểm tra sau đây sử dụng xđể thể hiện các ghi chú và .s để thể hiện phần còn lại. Đầu vào được đưa ra theo thứ tự n, sau đó k.

1 1    ->  x
3 2    ->  xx.
5 5    ->  xxxxx
8 2    ->  x...x...
8 5    ->  x.xx.xx.
8 7    ->  xxxxxxx.
10 1   ->  x.........
11 5   ->  x.x.x.x.x..
12 7   ->  x.xx.x.xx.x.
16 6   ->  x..x.x..x..x.x..
34 21  ->  x.xx.x.xx.xx.x.xx.x.xx.xx.x.xx.x.x
42 13  ->  x...x..x..x..x...x..x..x..x...x..x..x..x..
42 18  ->  x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.

Chấm điểm

Đây là mã golf, vì vậy mã trong ít byte nhất sẽ thắng.

Câu trả lời:


5

CJam, 37 34 30 27 24 byte

3 byte được lưu bởi user23013.

q~,f>{_(a-W<}{e`:a:e~z}w

Điều này có đầu vào là kđầu tiên, nthứ hai. Nó sử dụng 10để chỉ ghi chú và phần còn lại, tương ứng.

Hãy thử nó ở đây. Ngoài ra, đây là một khai thác thử nghiệm chạy tất cả các trường hợp thử nghiệm nhất định (hoán đổi thứ tự đầu vào) và cũng định dạng lại đầu ra để sử dụng x.để so sánh dễ dàng hơn với các giải pháp tham chiếu. (Các kết quả xuất hiện trong đầu vào của khai thác thử nghiệm bị loại bỏ trước khi chạy mã. Chúng có thể được gỡ bỏ an toàn mà không ảnh hưởng đến chương trình.)

Giải trình

q~                       e# Read and eval the input, dumping k and n on the stack.
  ,                      e# Create a range [0 .. n-1]
   f>                    e# For each of them, check if it's less than k.
                         e# This gives k 1s and n-k 0s.
     {      }{        }w e# While the first block yields a truthy result, execute
                         e# the second block.
      _                  e# Duplicate the array.
       (a-               e# Remove all instances of core sequences.
          W<             e# Remove one remainder sequence if there is one. This
                         e# gives an empty array (falsy) whenever there are less
                         e# than two remainder sequences.
              e`         e# Run-length encode. I.e. this turns an array into a list
                         e# of pairs of run-length and element.
                :a:e~    e# Wrap each RLE pair in an array and RLD it. This
                         e# partitions the array into cores and remainders.
                     z   e# Zip the two parts, interleaving cores and remainders.

Quá trình này các mảng được lồng rất sâu, nhưng phần quan trọng là tất cả các lõi (và tất cả các phần còn lại) luôn có cùng cấu trúc lồng nhau, vì vậy chúng vẫn bằng nhau. CJam tự động in nội dung ngăn xếp vào cuối chương trình và bỏ hoàn toàn các dấu phân cách mảng, do đó cấu trúc này cũng không ảnh hưởng đến đầu ra.


2 hoặc 3 byte ngắn hơn : q~\,f>.
jimmy23013

@ user23013 Ồ, thật là gọn gàng! Cảm ơn bạn. :)
Martin Ender

Đối với 3 byte, tôi có nghĩa là đầu vào có thể theo thứ tự.
jimmy23013

@ user23013 Ồ đúng rồi, tôi quên mất điều đó.
Martin Ender

1

Haskell, 125 byte

r=replicate
g z(a:b)(c:d)=g((a++c):z)b d
g z x y=(z,x++y)
f(x,y)|length y>1=f$g[]x y|1<2=concat$x++y
n#k=f(r k "x",r(n-k)".")

Ví dụ sử dụng: 42 # 13-> x...x..x..x..x...x..x..x..x...x..x..x..x...

fcó hai tham số: danh sách lõi và phần còn lại. Nó sẽ nén cả hai danh sách (thông qua g) và tự gọi lại hoặc dừng lại nếu phần còn lại quá ngắn. Các chức năng chính #tạo ra các danh sách bắt đầu và các cuộc gọi f.


1

Con trăn, 85

f=lambda n,k,a='1',b='0':n-k<2and a*k+b*(n-k)or[f(n-k,k,a+b,b),f(k,n-k,a+b,a)][2*k>n]

Các giải pháp đệ quy tự nhiên. Các tham số (n,k,a,b)đại diện cho lõi của k a's theo sau là phần còn lại của n-k b's.

Giải pháp này không hiệu quả vì cả hai cuộc gọi đệ quy fđược đánh giá, gây ra số lượng cuộc gọi theo cấp số nhân.

Tôi đã cố gắng nén lời mời có điều kiện fnhư

f(max(n-k,k),min(n-k,k),a+b,[a,b][2*k<n])
f(*[n-k,k,k,n-k,b,a][2*k>n::2]+[a+b])

nhưng không có cái nào ngắn hơn

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.