ตัดโซ่ทอง


32

นักเดินทางต้องพักเป็นเวลาnวันในโรงแรมนอกเมือง เขาไม่มีเงินสดและบัตรเครดิตของเขาหมดอายุ แต่เขามีโซ่ทองกับnการเชื่อมโยง

กฎในโรงแรมนี้คือผู้อยู่อาศัยควรจ่ายค่าเช่าทุกเช้า นักเดินทางมาถึงข้อตกลงกับผู้จัดการเพื่อจ่ายลิงค์หนึ่งของโซ่ทองในแต่ละวัน แต่ผู้จัดการยังต้องการให้นักเดินทางควรสร้างความเสียหายให้กับโซ่น้อยที่สุดในขณะที่จ่ายเงินทุกวัน กล่าวอีกนัยหนึ่งเขาต้องหาวิธีแก้ปัญหาเพื่อตัดลิงก์ให้น้อยที่สุดเท่าที่จะทำได้

การตัดการเชื่อมโยงสร้างสาม subchains: หนึ่งประกอบด้วยการเชื่อมโยง cut เท่านั้นและอีกหนึ่งในแต่ละด้าน ตัวอย่างเช่นการตัดลิงค์ที่สามของสายโซ่ยาว 8 จะสร้างความยาวย่อย [2, 1, 5] ผู้จัดการมีความสุขที่จะทำการเปลี่ยนแปลงดังนั้นนักเดินทางสามารถชำระเงินในวันแรกด้วยสายโซ่ยาว 1 จากนั้นวันที่สองพร้อมสายโซ่ยาว 2 เพื่อรับห่วงโซ่แรกคืน

รหัสของคุณควรป้อนความยาว nและออกรายการลิงก์เพื่อตัดความยาวต่ำสุด

กฎ :

  • nเป็นจำนวนเต็ม> 0
  • คุณสามารถใช้การจัดทำดัชนีแบบอิง 0 หรือ 1 ตามลิงก์
  • สำหรับตัวเลขบางตัวการแก้ปัญหานั้นไม่ซ้ำกัน ตัวอย่างเช่นถ้าn = 15ทั้งสอง[3, 8]และ[4, 8]เป็นผลลัพธ์ที่ถูกต้อง
  • คุณสามารถส่งคืนรายการหรือพิมพ์ด้วยตัวคั่นที่เหมาะสม
  • นี่คือดังนั้นโค้ดที่สั้นที่สุดในหน่วยไบต์ชนะ

กรณีทดสอบ :

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

ตัวอย่างรายละเอียด

สำหรับn = 15 การตัดลิงก์ 3 และ 8 ให้ผลลัพธ์เป็นความยาว[2, 1, 4, 1, 7]ย่อย นี่เป็นวิธีแก้ปัญหาที่ถูกต้องเพราะ:

 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

ไม่มีวิธีแก้ปัญหาที่มีเพียงการตัดเพียงครั้งเดียวดังนั้นนี่จึงเป็นทางออกที่ดีที่สุด

ภาคผนวก

โปรดทราบว่าปัญหานี้เกี่ยวข้องกับการแบ่งจำนวนเต็ม เรากำลังหาพาร์ติชันPของnซึ่งจำนวนเต็มทั้งหมดจาก 1 ถึงnมี patition อย่างน้อยหนึ่งตัวที่เป็นเซตย่อยของ P

นี่คือวิดีโอ YouTubeเกี่ยวกับอัลกอริทึมที่เป็นไปได้สำหรับปัญหานี้


ฉันไม่เข้าใจข้อมูลอ้างอิง "ทำการเปลี่ยนแปลง" ของคุณ ในตัวอย่างที่โพสต์ของคุณในวันที่สองคุณชำระเงินด้วยเชน 2-link (และรับ 1-link-chain (ซึ่งคุณจ่ายไปเมื่อวันก่อน) กลับมาเป็นการเปลี่ยนแปลงตามคำอธิบายของคุณ) 1+2แต่ในวันที่สามคุณชำระเงินด้วย 2-link-chain อันที่สองมาจากไหน
Flater

4
@Flater ผู้จัดการมีอยู่แล้ว เราเพียงจ่ายเพิ่มเติม อันที่จริงแล้ว RHS เป็นลิงค์ที่ผู้จัดการเป็นเจ้าของในแต่ละวัน
polfosol ఠ_ఠ

คำตอบ:


15

05AB1E , 23 11 8 ไบต์

ΔÍN-;иg=

ลองออนไลน์!

ใช้การจัดทำดัชนีแบบ 0

คำอธิบาย:

             # 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

иgดูเหมือนว่า noop แต่จริงๆแล้วมันทำสองสิ่งที่มีประโยชน์: มันตัดให้เป็นจำนวนเต็ม ( ;คืนค่าทศนิยม) และมันจะขัดข้องล่ามถ้า x เป็นลบ (นี่คือเงื่อนไขการออกเพียงอย่างเดียว)


โซลูชัน 23 ไบต์ใช้วิธีที่แตกต่างกันมากดังนั้นนี่คือสำหรับลูกหลาน: ÅœʒR2äθP}ʒæOê¥P}θ2äθη€O( TIO , คำอธิบาย )


2
ฉันได้ลบคำตอบของฉัน ฉันอายุ 42 ปีและคุณอายุ 11 ปีมีความแตกต่างกันมากเกินไปสำหรับฉันที่จะไม่รู้สึกอายฮ่าฮ่า ;) Nice คำตอบแม้ว่าและฮ่า ๆ Ø.Øที่ คุณลองทำสิ่งสุ่มเพื่อให้ทั้งพื้นและแผนที่ลบทั้งหมด-1หรือไม่ คำตอบที่ดีมากและสั้นกว่าที่ฉันคาดไว้มาก ฉันกำลังคิดประมาณ 20 ไบต์หลังจากที่ฉันโพสต์ข้อความไม่ดีขนาด 42 ไบต์
Kevin Cruijssen

2
@KevinCruijssen Nnope Ø.Øเป็นความคิดแรกของฉัน ความคิดเห็นของคุณเป็นแรงบันดาลใจให้ผมลองสิ่งสุ่ม: ผมพบว่า®Ÿà, ï®Mและที่สำคัญมากขึ้นиgซึ่งอัตราผลตอบแทนนี้ดี 8 byter ฉันมักจะพบว่ามันน่ารำคาญที่ osabie ไม่ต้องการทำอะไรมากไปกว่าการล่มในหลาย ๆ กรณี (หารด้วย 0, พิมพ์ผิด, ฯลฯ ) ดังนั้นความผิดพลาดนี้จะมีประโยชน์
Grimmy

2
Hehe, 05AB1E ควรจะไม่ผิดพลาด แต่คุณพูดถูกว่าบางครั้งมันก็น่ารำคาญนิดหน่อยที่มันไม่เคยทำ .. ในมรดกฉันไม่รู้ว่าจะผิดพลาดได้อย่างไรและในอดีตเราก็มีการแบ่งอย่างชัดเจนด้วย ข้อผิดพลาดเป็นศูนย์เราสามารถโทรด้วยตนเอง xD ในเวอร์ชั่นใหม่ยังคงมีข้อผิดพลาดค่อนข้างบ่อยเมื่อให้อาร์กิวเมนต์ที่ไม่ถูกต้องกับบิวอินบางตัว และ -3 ดีอีกครั้ง
Kevin Cruijssen

2
msgstr "ขัดข้องล่ามถ้า x เป็นลบ (นี่เป็นเงื่อนไขการออกเพียงอย่างเดียว)" - ฉันรักสิ่งนั้น
John Dvorak

9

Python 2 , 75 ไบต์

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

ลองออนไลน์!


คำอธิบาย:

สร้างลำดับของส่วน 'ไบนารี' ด้วยหมายเลขฐานที่ตรงกับจำนวนการตัด

เช่น:

63 สามารถทำได้ใน 3 การตัดซึ่งหมายถึงพาร์ติชันในฐาน -4 (เนื่องจากเรามี 3 วงเดียว):

บาดแผล: 5, 14, 31ซึ่งให้โซ่ของ4 1 8 1 16 1 32(เรียงลำดับ:1 1 1 4 8 16 32 )

หมายเลขทั้งหมดสามารถทำได้:

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

ตัวอย่างอื่น ๆ :

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
คุณไม่ควรเพิ่มf=ในการเริ่มต้นหรือ เนื่องจากคุณใช้การเรียกไปยังfฟังก์ชัน lambda และฉันสามารถสันนิษฐานได้ว่าคุณอ้างถึงแลมบ์ดาเดียวกับที่คุณกำหนด
randomdude999

@ randomdude999 ใช่ฉันลืม ...
TFeld

@ randomdude999 กฎนั้นใช้ได้กับทุกภาษาหรือเพียงแค่ไพ ธ อน? สาเหตุที่ผมเห็นคำตอบจาวาสคริปต์ที่เป็นแลมบ์ดาบริสุทธิ์ในความท้าทายนี้ ...
เงา

3
@Shadow มันใช้กับทุกภาษา แต่เฉพาะกับ lambdas แบบเรียกซ้ำ
TFeld

1
@Shadow กฎทั่วไปมากขึ้นคือคุณไม่สามารถอ้างอิงบางสิ่งที่ไม่ได้กำหนดไว้ในรหัสของคุณหรือกำหนดไว้ในภาษาของคุณทั่วโลกเว้นแต่จะได้รับอนุญาตจากการท้าทายอย่างชัดเจน กรณีที่พบบ่อยที่สุดคือฟังก์ชั่นวนซ้ำ แต่กรณีนี้ใช้กับสถานการณ์อื่น คำตอบนี้เป็นอีกตัวอย่างหนึ่ง: fไม่เรียกซ้ำ แต่เป็นการอ้างอิงในโค้ดและต้องมีการตั้งชื่อ
Arnauld

8

R , 77 69 ไบต์

-8 ไบต์ขอบคุณ Aaron Hayman

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

ลองออนไลน์!

kk(k+1)2kn1,1,...,1k(k+1),2(k+1),4(k+1),8(k+1),...,(k+1)2k-1. ง่ายต่อการตรวจสอบว่าเพียงพอและเหมาะสมที่สุด

(เครือข่ายย่อยสุดท้ายอาจจำเป็นต้องทำให้สั้นลงหากเรามีความยาวเกินกว่าความยาวรวมของโซ่)

Ungolfed (อิงจากเวอร์ชั่นก่อนหน้านี้ที่คล้ายกัน):

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
}

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

If a(k) is the smallest integer n requiring k cuts, then a(k) is OEIS A134401.


I doubt it would help with the special case for n=1, but an alternative way to generate the cutoffs is the recurrence 1, 4, 4a(n-1)-4a(n-2).
Peter Taylor

@PeterTaylor I had a similar recurrence for computing k; this corresponds to OEIS A134401: oeis.org/A134401 But my implementation of the recurrence relation takes up more bytes than the current code.
Robin Ryder

A bit of rearrangement I got it down to 73. Try it online!
Aaron Hayman

@AaronHayman Thanks! Smart move using sum instead of match.
Robin Ryder

69 bytes and got rid of that if statement that was upsetting you: Try it online!
Aaron Hayman



2

C++, 109,107 bytes

-2 bytes thanks to 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<<',';}

The algorithm is similar to the Robin Ryder's answer. The code is written in a compilable, whole form. Try it!

Details:

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

This has a C variation with the same byte length (doesn't seem to need a separate answer):

#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);}

Two minor things to golf: =0 after k can be removed, since its 0 by default. std::cin>>n;while(++k<<k<n); can be for(std::cin>>n;++k<<k<n;);. I also have the feeling for(n-=k;n>0;k*=2,n-=k+1) can be simplified somehow by combining stuff, but not sure how. PS: Changing the comma-delimiter to a space looks slightly better since you don't see the trailing one imo, but this is purely cosmetic :)
Kevin Cruijssen

1
@KevinCruijssen Thanks, but some compilers don't assign a default value to non-static variables. So I thought =0 was necessary for portability ;) I also realized that the space after #include is not necessary.
polfosol ఠ_ఠ

อาโอเค. ฉันไม่รู้ C ++ เหมือนกันดังนั้นฉันจึงใช้คอมไพเลอร์ออนไลน์ที่คุณเชื่อมโยงในคำตอบของคุณเพื่อทดสอบบางสิ่ง :) คุณลืมการเปลี่ยนแปลงครั้งที่สองที่ฉันเสนอในความคิดเห็นของฉัน: while-loop เป็น for-loop และใส่std::cin>>nเข้าไปข้างใน
Kevin Cruijssen


1

เรติน่า 0.8.2 , 61 ไบต์

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

ลองออนไลน์! พอร์ตที่มีการจัดทำดัชนี 1 คำตอบของ @ Grimy คำอธิบาย:

.+
11,$&$*

เริ่มต้นด้วยN=2และอินพุตถูกแปลงเป็น unary

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

พยายามลบNจากอินพุตซ้ำหลายครั้งแล้วหารด้วย 2

1$2¶1$1,$3

หากสำเร็จให้จำมากกว่า 1 อินพุตในบรรทัดก่อนหน้าโดยเพิ่มขึ้น Nจากบรรทัดปัจจุบันและอัพเดตอินพุตเป็นค่าใหม่

1+,
1

ลบNและเพิ่มค่าสุดท้ายเพื่อให้เป็นดัชนี 1

1A`

ลบอินพุตต้นฉบับที่เพิ่มขึ้น

1+
$.&

แปลงผลลัพธ์เป็นทศนิยม


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