Cắt dây chuyền vàng


32

Một du khách cần ở lại n ngày trong một khách sạn bên ngoài thị trấn. Anh ta hết tiền và thẻ tín dụng của anh ta đã hết hạn. Nhưng anh ta có một chuỗi vàng với n liên kết.

Quy tắc trong khách sạn này là cư dân nên trả tiền thuê nhà mỗi sáng. Lữ khách đi đến một thỏa thuận với người quản lý để trả một liên kết của chuỗi vàng cho mỗi ngày. Nhưng người quản lý cũng yêu cầu khách du lịch nên tạo ra thiệt hại ít nhất có thể cho chuỗi trong khi trả tiền mỗi ngày. Nói cách khác, anh ta phải đưa ra một giải pháp để cắt càng ít liên kết càng tốt.

Cắt một liên kết tạo ra ba chuỗi con: một liên kết chỉ chứa liên kết cắt và một liên kết ở mỗi bên. Ví dụ, việc cắt liên kết thứ ba của chuỗi có độ dài 8 sẽ tạo ra các chuỗi con có độ dài [2, 1, 5]. Người quản lý rất vui khi thực hiện thay đổi, vì vậy khách du lịch có thể thanh toán vào ngày đầu tiên với chuỗi độ dài 1, sau đó là ngày thứ hai với chuỗi độ dài 2, lấy lại chuỗi đầu tiên.

Mã của bạn nên nhập độ dài n và xuất ra danh sách các liên kết cần cắt có độ dài tối thiểu.

Quy tắc :

  • n là số nguyên> 0.
  • Bạn có thể sử dụng lập chỉ mục dựa trên 0 hoặc 1 dựa trên các liên kết.
  • Đối với một số con số, giải pháp không phải là duy nhất. Ví dụ, nếu n = 15cả hai [3, 8][4, 8]là đầu ra hợp lệ.
  • Bạn có thể trả về danh sách hoặc in bằng bất kỳ dấu phân cách hợp lý nào.
  • Đây là , vì vậy mã ngắn nhất tính bằng byte sẽ thắng.

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

Input          Output (1-indexed)
1              []
3              [1]
7              [3]
15             [3, 8]
149            [6, 17, 38, 79]

Ví dụ chi tiết

Với n = 15, việc cắt các liên kết 3 và 8 dẫn đến các chuỗi con có độ dài [2, 1, 4, 1, 7]. Đây là một giải pháp hợp lệ vì:

 1 = 1
 2 = 2
 3 = 1+2
 4 = 4
 5 = 1+4
 6 = 2+4
 7 = 7
 8 = 1+7
 9 = 2+7
10 = 1+2+7
11 = 4+7
12 = 1+4+7
13 = 2+4+7
14 = 1+2+4+7
15 = 1+1+2+4+7

Không có giải pháp nào chỉ có một vết cắt tồn tại, vì vậy đây là một giải pháp tối ưu.

Phụ lục

Lưu ý rằng vấn đề này có liên quan đến phân vùng số nguyên. Chúng tôi đang tìm kiếm một phân vùng P của n sao cho tất cả các số nguyên từ 1 đến n có ít nhất một patition đó là một tập hợp con của P .

Đây là một video YouTube về một thuật toán có thể cho vấn đề này.


Tôi không hiểu tài liệu tham khảo "thay đổi" của bạn. Trong ví dụ được đăng của bạn, vào ngày thứ hai bạn thanh toán bằng chuỗi 2 liên kết (và nhận chuỗi 1 liên kết (mà bạn đã trả với ngày hôm trước) trở lại dưới dạng thay đổi, theo giải thích của bạn). Nhưng vào ngày thứ ba, bạn thanh toán bằng1+2 . Chuỗi 2 liên kết thứ hai đến từ đâu?
Flater

4
@Flater Người quản lý đã có nó. Chúng tôi chỉ trả tiền thêm. Trên thực tế, RHS là các liên kết mà người quản lý sở hữu mỗi ngày
polfosol _ఠ

Câu trả lời:


15

05AB1E , 23 11 8 byte

ΔÍN-;иg=

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

Sử dụng lập chỉ mục dựa trên 0.

Giải trình:

             # start from the implicit input
Δ            # loop forever
 Í           # subtract 2
  N-         # subtract the current iteration number
    ;        # divide by 2
     и       # create a list of length x
      g      # get the length of the list
       =     # print

иgTrông giống như một noop, nhưng nó thực sự có hai điều hữu ích: nó cắt ngắn thành một số nguyên ( ;trả về một số float) và nó làm hỏng trình thông dịch nếu x âm (đây là điều kiện thoát duy nhất).


Giải pháp 23 byte đã sử dụng một cách tiếp cận rất khác, do đó, đây là cho hậu thế: ÅœʒR2äθP}ʒæOê¥P}θ2äθη€O( TIO , giải thích ).


2
Tôi đã xóa câu trả lời của mình. Của tôi là 42 và của bạn là 11 là một sự khác biệt quá lớn để tôi không cảm thấy xấu hổ, haha. ;) Mặc dù câu trả lời tốt đẹp, và lol tại Ø.Ø. Bạn đã thử một số điều ngẫu nhiên để cả hai tầng và ánh xạ tất cả các tiêu cực đến -1? Bất kể, câu trả lời rất hay và ngắn hơn nhiều so với tôi dự đoán. Tôi đã suy nghĩ khoảng 20 byte sau khi tôi đăng bài 42 -ter xấu của mình.
Kevin Cruijssen

2
@KevinCruijssen Nnope, Ø.Øthực sự là ý tưởng đầu tiên của tôi. Cảm nhận của bạn cảm hứng cho tôi để thử những điều ngẫu nhiên: Tôi tìm thấy ®Ÿà, ï®Mvà quan trọng hơn, иg, trong đó sản lượng này đẹp 8-byter. Tôi luôn thấy khó chịu khi osabie thích không làm gì hơn là bị rơi trong nhiều trường hợp (div bằng 0, sai loại, v.v.), vì vậy sự cố này sẽ có ích.
Grimmy

2
Hehe, 05AB1E được cho là sẽ không bao giờ gặp sự cố, nhưng bạn nói đúng rằng đôi khi hơi phiền phức, nó không bao giờ xảy ra .. Trong di sản tôi thậm chí không biết làm thế nào để sụp đổ, và trong quá khứ chúng tôi thậm chí đã có một sự phân chia rõ ràng bởi không có lỗi chúng tôi có thể gọi bằng tay. xD Trong phiên bản mới, nó vẫn gặp lỗi khá thường xuyên khi đưa ra các đối số không chính xác cho các nội dung nhất định. Và tốt đẹp -3 một lần nữa.
Kevin Cruijssen

2
"làm hỏng trình thông dịch nếu x âm (đây là điều kiện thoát duy nhất)." - Tôi thích điều đó
John Dvorak

9

Con trăn 2 , 75 byte

f=lambda n,i=0:n>=i<<i and f(n,i+1)or[min(n,2**j*i-i+j)for j in range(1,i)]

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


Giải trình:

Xây dựng một chuỗi các khối 'nhị phân', với số cơ sở khớp với số lần cắt.

Ví dụ:

63 có thể được thực hiện trong 3 lần cắt, có nghĩa là một phân vùng trong cơ sở 4 (vì chúng tôi có 3 vòng đơn):

Cuts : 5, 14, 31, cung cấp chuỗi 4 1 8 1 16 1 32(được sắp xếp 1 1 1 4 8 16 32:).

Tất cả các số có thể được thực hiện:

1       1
2       1 1
3       1 1 1
4       4
...
42      1 1 8 32
...
62      1 1 4 8 16 32
63      1 1 1 4 8 16 32

Những ví dụ khác:

18: 4,11        ->  3 1 6 1 7
27: 5,14,27     ->  4 1 8 1 13 1
36: 5,14,31     ->  4 1 8 1 16 1 5
86: 6,17,38,79  ->  5 1 10 1 20 1 40 1 7

1
Bạn không nên thêm f=vào đầu? Vì bạn sử dụng lệnh gọi ftrong hàm lambda và tôi chỉ có thể giả sử rằng bạn tham chiếu đến cùng lambda mà bạn đang xác định.
Randomdude999

@ Randomdude999, Vâng, tôi đã quên ...
TFeld

@ Randomdude999 quy tắc đó có áp dụng cho tất cả các ngôn ngữ hay chỉ python? Vì tôi thấy một câu trả lời javascript là lambda thuần túy trong thử thách này ...
Shadow

3
@Shadow Nó áp dụng cho tất cả các ngôn ngữ, nhưng chỉ dành cho lambdas đệ quy.
TFeld

1
@Shadow Một quy tắc chung hơn là bạn không thể tham chiếu một cái gì đó không được xác định trong mã của bạn hoặc không được xác định toàn cầu trong ngôn ngữ của bạn, trừ khi được thách thức cho phép rõ ràng. Trường hợp phổ biến nhất là một hàm đệ quy, nhưng điều này áp dụng cho các tình huống khác. Câu trả lời này là một ví dụ khác: fkhông phải là đệ quy, nhưng nó được tham chiếu trong mã và do đó phải được đặt tên.
Arnauld

8

R , 77 69 byte

-8 byte nhờ Aaron Hayman

pmin(n<-scan(),0:(k=sum((a=2:n)*2^a<=n))+cumsum((k+2)*2^(0:k))+1)[-n]

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

kk(k+1)2kn1,1,,1k(k+1),2(k+1),4(k+1),số 8(k+1),Giáo dục,(k+1)2k-1

(Chuỗi con cuối cùng có thể cần được rút ngắn hơn nếu chúng ta vượt quá tổng chiều dài của chuỗi.)

Ungolfed (dựa trên phiên bản tương tự trước đó):

n = scan()                            # read input
if(n - 1){                            # If n==1, return NULL
  k = match(F, (a = 2:n) * 2 ^ a > n) # compute k
  b = (k + 1) * 2 ^ (1:k - 1)         # lengths of subchains
  c = 1:k + cumsum(b)                 # positions of cuts
  pmin(c, n )                         # if last value is >n, coerce it to n
}

kkkk+12k+12k+2 , sau đó4k+4... Vì vậy, tối đa chúng ta có thể thoát ra khỏi k cắt giảm có được bằng cách tổng hợp tất cả các độ dài, mà mang lại (k+1)2k-1.)

Nếu một(k) là số nguyên nhỏ nhất n yêu cầu k cắt, sau đó một(k)OEIS A134401 .


Tôi nghi ngờ nó sẽ giúp ích cho trường hợp đặc biệt n=1, nhưng một cách khác để tạo ra các điểm cắt là sự tái phát 1, 4, 4a(n-1)-4a(n-2).
Peter Taylor

@PeterTaylor Tôi bị tái phát tương tự cho máy tính k; điều này tương ứng với OEIS A134401: oeis.org/A134401 Nhưng việc thực hiện quan hệ lặp lại của tôi chiếm nhiều byte hơn mã hiện tại.
Robin Ryder

Một chút sắp xếp lại tôi đã giảm xuống 73. Hãy thử trực tuyến!
Aaron Hayman

@AaronHayman Cảm ơn! Di chuyển thông minh sử dụng sumthay vì match.
Robin Ryder

69 byte và loại bỏ điều đó nếu câu lệnh làm bạn khó chịu: Hãy thử trực tuyến!
Aaron Hayman



2

C ++, 109 , 107 byte

-2 byte nhờ Kevin

#include<iostream>
main(){int n,k=0;for(std::cin>>n;++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)std::cout<<n<<',';}

Thuật toán tương tự như câu trả lời của Robin Ryder. Mã được viết dưới dạng tổng hợp, toàn bộ.Thử nó!

Chi tiết:

std::cin>>n;               // get the value of n as input
while(++k<<k<n);           // determine k
for(n-=k;n>0;k*=2,n-=k+1)  // we don't need n, so the lengths...
    std::cout<<n<<' ';     // of links are subtracted repeatedly

Điều này có một biến thể C có cùng độ dài byte (dường như không cần câu trả lời riêng):

#include<stdio.h>
main(){int n,k=0;for(scanf("%d",&n);++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)printf("%d,",n);}

Hai điều nhỏ đối với golf: =0sau kcó thể được loại bỏ, vì nó 0theo mặc định. std::cin>>n;while(++k<<k<n);có thể for(std::cin>>n;++k<<k<n;);. Tôi cũng có cảm giác for(n-=k;n>0;k*=2,n-=k+1)có thể được đơn giản hóa bằng cách nào đó bằng cách kết hợp các công cụ, nhưng không biết làm thế nào. Tái bút: Thay đổi dấu phẩy thành không gian có vẻ tốt hơn một chút vì bạn không thấy dấu imo, nhưng đây hoàn toàn là mỹ phẩm :)
Kevin Cruijssen

1
@KevinCruijssen Cảm ơn, nhưng một số trình biên dịch không gán giá trị mặc định cho các biến không tĩnh. Vì vậy, tôi nghĩ =0là cần thiết cho tính di động;) Tôi cũng nhận ra rằng không gian sau đó #includelà không cần thiết.
polfosol _ఠ

À được rồi Tôi không biết rõ về C ++, vì vậy tôi đã sử dụng trình biên dịch trực tuyến mà bạn đã liên kết trong câu trả lời của mình để kiểm tra một số thứ. :) Bạn đã quên thay đổi thứ hai mà tôi đã đề xuất trong nhận xét của mình: vòng lặp while thành vòng lặp for và đặt std::cin>>nbên trong nó.
Kevin Cruijssen


1

Võng mạc 0.8.2 , 61 byte

.+
11,$&$*
+`\b(1+),(\1(1*)1?\3)$
1$2¶1$1,$3
1+,
1
1A`
1+
$.&

Hãy thử trực tuyến! Cổng 1 chỉ mục của câu trả lời của @ Grimy. Giải trình:

.+
11,$&$*

Bắt đầu với N=2và đầu vào được chuyển đổi thành unary.

+`\b(1+),(\1(1*)1?\3)$

Liên tục cố gắng trừ đi Ntừ đầu vào và sau đó chia cho 2.

1$2¶1$1,$3

Nếu thành công, hãy nhớ 1 nhiều hơn đầu vào trên dòng trước, tăng Ntrên dòng hiện tại và cập nhật đầu vào thành giá trị mới.

1+,
1

Xóa Nvà tăng giá trị cuối cùng để nó cũng được lập chỉ mục 1.

1A`

Loại bỏ đầu vào ban đầu tăng.

1+
$.&

Chuyển đổi kết quả thành số thập phâ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.