ตรวจสอบว่าระบบเหรียญเป็นมาตรฐานหรือไม่


48

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

นำตัวอย่างต่อไปนี้:

เรามี 4 ¢, 3 ¢และ 1 ¢เหรียญ เราต้องการทำ 6 ¢

อัลกอริทึมของแคชเชียร์จะเลือกเหรียญที่ใหญ่ที่สุดเป็นอันดับแรก (หนึ่ง 4 ¢เพื่อเริ่มต้น) และลบและทำซ้ำ ซึ่งจะส่งผลให้หนึ่ง 4 ¢เหรียญและสอง 1 ¢เหรียญรวมเป็น 3 เหรียญ

โชคไม่ดีที่อัลกอริทึมมีวิธีทำ 6 ¢ด้วยสองเหรียญเท่านั้น (สอง 3 เหรียญ)

ระบบการเปลี่ยนแปลงจะได้รับการพิจารณาว่าเป็นบัญญัติ iff สำหรับค่าจำนวนเต็มทั้งหมดอัลกอริทึมของแคชเชียร์จะค้นหาจำนวนเหรียญที่เหมาะสมที่สุด

งาน

ภารกิจของคุณคือการใช้ระบบเป็นคอนเทนเนอร์ที่ไม่ได้เรียงลำดับหรือเรียงลำดับของจำนวนเต็มแทนค่าเหรียญและเอาท์พุทเป็นค่าจริงหากอินพุตของระบบเป็นที่ยอมรับและไม่แน่นอน

โปรแกรมของคุณควรทำงานได้กับทุกระบบที่สามารถสร้างมูลค่าได้ (เช่นทุกระบบจะมีเหรียญ 1))

นี่คือรหัสของกอล์ฟอย่างน้อยไบต์ชนะ

กรณีทดสอบ

รายการนี้ไม่ครบถ้วนสมบูรณ์โปรแกรมของคุณควรทำงานกับอินพุตที่ถูกต้องทั้งหมด

1, 3, 4       -> 0
1, 5, 10, 25  -> 1
1, 6, 10, 25  -> 0
1, 2, 3       -> 1
1, 8, 17, 30  -> 0
1, 3, 8, 12   -> 0
1, 2, 8, 13   -> 0
1, 2, 4, 6, 8 -> 1

@Geobits ไม่ได้ในทุกกรณีมันมีความหมายมากกว่านั้นความแตกต่างที่เพิ่มขึ้นหรือเท่ากันจากเหรียญที่เล็กที่สุดถึงใหญ่ที่สุด
JörgHülsermann

@ JörgHülsermannนั่นก็ไม่ดีพอเหมือนกัน [1, 6, 13] มีความแตกต่างเพิ่มขึ้น แต่ก็ยังคงล้มเหลวในบางอย่างเช่น 18 (13 + 1 * 5 แทนที่จะเป็น 6 * 3)
Geobits

16
เหล่านี้เรียกว่าCanonical ระบบเหรียญ กระดาษสั้นนี้ให้อัลกอริทึมเวลาพหุนามสำหรับการตรวจสอบว่าระบบเหรียญเป็นที่ยอมรับ (แม้ว่าวิธีการที่มีประสิทธิภาพน้อยกว่าอาจจะเป็นนักเล่นกอล์ฟ) กรณีการทดสอบที่น่าสนใจคือการทำให้ 37 เซนต์25, 9, 4, 1(จากการโพสต์นี้ math.SE ) - แม้ว่าแต่ละเหรียญมีขนาดใหญ่กว่าผลรวมของคนเล็กที่ไม่โลภเต้นโลภ25, 4, 4, 4 25, 9, 1, 1, 1
xnor

1
@xnor โปรดทราบว่า9, 4, 1-> 4, 4, 4การดีกว่า9, 1, 1, 1เป็นตัวอย่างที่กระชับ
isaacg

คำตอบ:


9

Haskell, 94 87 82 ไบต์

f s=and[j i-2<j(i-x)|let j i=last$0:[1+j(i-x)|x<-s,x<i],i<-[1..2*last s],x<-s,x<i]

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

วิธีนี้จะถือว่าอินพุตถูกเรียงลำดับ

หลักฐานการตรวจสอบถึงสองเท่าของจำนวนที่ใหญ่ที่สุดคือพอ: สมมติว่าระบบไม่เป็นที่ยอมรับสำหรับบางหมายเลขiและปล่อยให้เป็นหมายเลขที่ใหญ่ที่สุดในรายการไม่ได้มีขนาดใหญ่กว่าk iคิดว่าระบบนี้เป็นที่ยอมรับสำหรับตัวเลขทั้งหมดน้อยกว่าi >= 2ki

ใช้เวลาบางส่วนวิธีที่ดีที่สุดที่จะทำให้ออกมาจากเหรียญและถือว่ามันไม่ได้มีเหรียญi kถ้าเราทิ้งเหรียญหนึ่งเหรียญผลรวมของเหรียญใหม่จะต้องมากกว่าkและเล็กกว่าi- แต่อัลกอริทึมของแคชเชียร์ที่หมายเลขนี้จะใช้kเหรียญ - ดังนั้นเหรียญชุดนี้สามารถถูกแทนที่ด้วยชุดเหรียญที่เท่ากัน บรรจุเหรียญkและดังนั้นจึงมีชุดของเหรียญที่บรรจุเหรียญkสำหรับหมายเลขiและจากการเหนี่ยวนำอัลกอริทึมของแคชเชียร์จะส่งกลับตัวเลือกที่ดีที่สุด

อาร์กิวเมนต์นี้แสดงให้เห็นว่าเราเพียงแค่ต้องตรวจสอบจนกว่าผลรวมขององค์ประกอบที่ใหญ่ที่สุดทั้งสอง - แต่มันยาวกว่านั้น

แก้ไข: ปิดห้าไบต์ขอบคุณØrjan Johansen!


1
คุณสามารถบันทึกไบต์โดยใช้แทนlet whereคุณสามารถใส่มันเป็น|let ...ยามรูปแบบหลังจากf sหรือภายในรายการความเข้าใจ
Ørjan Johansen

1
j i=last$0:[1+j(i-k)|k<-s,k<i]อีกสี่ไบต์ด้วย
Ørjan Johansen

5

Pyth, 18 15 ไบต์

!x#eST.gsky_S*e

ชุดทดสอบ

แรงเดรัจฉานแตกต่างกัน สิ่งนี้เริ่มต้นด้วยการสะสมเหรียญทั้งหมดด้วยสูงสุด k ของแต่ละเหรียญโดยที่ k เป็นเหรียญที่ใหญ่ที่สุดซึ่งถือว่าเป็นเหรียญสุดท้าย ฉันเชื่อว่าสิ่งนี้เพียงพอที่จะสร้างเหรียญสองชุดที่มีผลรวมเท่ากันหนึ่งโลภและสั้นลงเมื่อใดก็ตามที่มีคู่ดังกล่าวอยู่

ฉันก็หาคู่ดังกล่าวเป็นดังนี้:

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

คำอธิบาย:

!x#eST.gsky_S*e
!x#eST.gsky_S*eQQ   Variable introduction.
                    Q = eval(input()) - sorted list of coins.
              eQ    Greatest coin in the list
             *  Q   Repeat that many times.
            S       Sort the coins
           _        Reverse, so we have the coins in descending order.
          y         Form all subsets, in increasing size then
                    decreasing lexicographic order.
      .gsk          Group by sum
 x#                 Filter by the index in the group of
   eST              The last element lexicographically (greedy solution).
!                   Logically negate.

ดีมาก ๆ - ทำไมคุณถึงติดแฮงเอาท์กับ herokuapp สำหรับ [1, 2, 4, 6, 8] และถูกฆ่า/opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137ที่ TIO? เพิ่งจะจำไม่ได้
Jonathan Allan

วิธีนี้ใช้หน่วยความจำ 2 ^ (เหรียญ NUM * เหรียญสุดท้าย) ดังนั้นสำหรับตัวอย่างของคุณ 2 ^ 40 มีเครื่องไม่มากกับ RAM ขนาดเทราไบต์
isaacg

ฉันคิดว่าอาจเป็นกรณีนี้คำอธิบายของอัลกอริทึมนั้นสมเหตุสมผล แต่ฉันไม่ได้คำนวณตัวเลข - เร็วมากเลย!
Jonathan Allan

5

PHP, 323 ไบต์

เช่นเดียวกับที่คนอื่น ๆ นับเหรียญจนกระทั่งผลรวมขององค์ประกอบสองชิ้นสุดท้ายในอาร์เรย์

<?function t($g){rsort($g);$m=array_slice($g,1);for($y=1,$i=$g[0];$i<$g[0]+$m[0];$i++){$a=$b=$i;$p=0;$r=$s=[];while($a||$b){$o=$n=0;$g[$p]<=$a?$a-=$r[]=$g[$p]:$o=1;($m[$p]??1)<=$b?$b-=$s[]=$m[$p]:$n=1;$p+=$o*$n;}$y*=count($r)<=count($s);}return$y;}for($i=0,$t=1;++$i<count($a=$_GET[a]);)$t*=t(array_slice($a,0,$i+1));echo$t;

คำตอบที่ดีที่สุดและยาวที่สุดของฉันฉันเชื่อ> 370 ไบต์

ฉันให้เฉพาะรุ่นที่ขยายเท่านั้นเพราะมันนานกว่านั้นคำตอบของฉันก่อนหน้านี้

for($x=1,$n=0,$f=[];++$n<count($a)-1;){
$z=array_slice($a,0,$n+1);
$q=$a[$n]-$a[$n-1];
$i=array_fill(1,$c=max($a[$n+1]??1,11),"X");#$q*$a[$n]
$f=range($a[$n],$c,$q);

$f[]=2*$a[$n];
for($d=[$z[$n]],$j=0;$j<$n;){
   $f[]=$a[$n]+$d[]=$z[$n]-$z[$j++]; 
}

while($f){
    $i[$t=array_pop($f)]="T";
    foreach($d as $g)
    if(($l=$t+$g)<=$c)$f[]=$l;
}

foreach($i as$k=>$v){
    if(in_array($k,$z))$i[$k]="S";
}
#var_dump($i);
if($i[$a[$n+1]]=="X")$x*=0;
}
echo$x;

คำอธิบายสำหรับคำตอบนี้

เวอร์ชั่นออนไลน์

  1. ตั้งค่าทั้งหมดในอาร์เรย์เป็น false == X

  2. ตั้งค่าตัวเลขทั้งหมดในอาร์เรย์ที่คุณควบคุมเป็น S

  3. พบความแตกต่างระหว่าง S สุดท้ายและ S อื่น ๆ หรือ 0

  4. เริ่มต้นที่ S สุดท้ายในอาร์เรย์

  5. ตั้งค่าตัวเลขทั้งหมดเป็น D โดยที่ S + ล่าสุดหนึ่งในความแตกต่างทั้งหมด

  6. เริ่มต้นที่ D

  7. ชุด "T" ถึงค่า D ในอาร์เรย์

  8. GOTO 5 ทำซ้ำกับ DI ทั้งหมดที่พบไม่ได้อยู่ในรหัส

  9. หากรายการถัดไปใน Array มี X มันจะเป็นจริงหรือไม่จริง

ขั้นตอนเพิ่มเติมความแตกต่างคือในกรณีในตัวอย่าง 3 ระหว่าง 1 และ 4 คือ 2 X ซึ่งหมายความว่าคุณต้องการ D ที่สองตามขั้นตอนที่ 5 หลังจากค่านี้ในกรณีนี้ 10 เป็นกรณีทั้งหมดจริงฉันสามารถเห็นได้ว่ามีความสัมพันธ์ ระหว่างความแตกต่างและจำนวนในอาร์เรย์ที่คุณควบคุมเพื่อคำนวณจำนวน D (ขั้นตอนที่ 5) ที่คุณต้องได้รับจากจุดก่อนที่คุณจะพบคดีเท็จครั้งล่าสุด

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

  1. ตั้งศัตรูคนแรกที่ 1 + วินาทีสุดท้าย

  2. จากจุดนี้เพิ่มแต่ละค่าในอาร์เรย์เพื่อตั้งค่าศัตรูต่อไป

  3. เริ่มต้นด้วยศัตรูคนสุดท้ายไปที่ 2

ถ้าตอนนี้คุณมีศัตรูและคดีจริงอยู่ในนั้นความน่าจะเป็นที่เพิ่มขึ้นที่การนับสามารถเหมือนกันเมื่อมี D มากขึ้นความน่าจะเป็นจะลดลง

table{width:80%}
td,th{width:45%;border:1px solid blue;}
<table>
  <caption>Working [1,4]</caption>
<tr><th>Number</th><th>Status</th></tr>
<tr><td>1</td><td>S</td></tr>
<tr><td>2</td><td>X</td></tr>
<tr><td>3</td><td>X</td></tr>
<tr><td>4</td><td>S</td></tr>
<tr><td>5</td><td>X</td></tr>
<tr><td>6</td><td>X</td></tr>
<tr><td>7</td><td>D3</td></tr>
<tr><td>8</td><td>D4</td></tr>
<tr><td>9</td><td>X</td></tr>
<tr><td>10</td><td>D3D3</td></tr>
<tr><td>11</td><td>D4D3</td></tr>
<tr><td>12</td><td>D4D4</td></tr>
<tr><td>13</td><td>D3D3D3</td></tr>
<tr><td>14</td><td>D4D3D3</td></tr>
<tr><td>15</td><td>D4D4D4</td></tr>
<tr><td>16</td><td>D4D4D3</td></tr>
</table>
<ul>
  <li>S Number in Array</li>
  <li>D Start|End point TRUE sum Differences from last S</li>
  <li>X False</li>
  </ul>

บวก Bytes Thank You @JonathanAllan ให้ฉันทำข้อสอบผิด
262 Bytes เกือบ แต่ไม่ดีพอ 4 testcase ผิดในขณะนี้

กรณีทดสอบ [1,16,256] ก่อนหน้านี้ควรเป็นจริงหลังจากเท็จ

<?for($q=[1],$i=0,$t=1,$w=[0,1];++$i<count($a=$_GET[v]);$w[]=$a[$i],$q[]=$m)($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2])&&((($x)%2)==(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)||(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0||in_array($m,$w))?:$t=0;echo$t;

เรียงลำดับจากน้อยไปมาก

คำอธิบาย

for($q=[1],$i=0,$t=1,$w=[0,1] # $t true case $q array for modulos $w checke values in the array
;++$i<count($a=$_GET[v])   #before loop
;$w[]=$a[$i],$q[]=$m) # after loop $q get the modulo from the result and fill $w with the checked value

($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2]) 
# First condition difference between $a[i] and $a[$i-1] is greater or equal $a[$i-1] and $a[$i-2]
# if $a[$-1] == 1 $a[$i-2] will be interpreted as 0
&&  ## AND Operator with the second condition
(
(($x)%2)==   # See if the difference is even or odd
(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)
# After that we multiply the result with the lower value *$a[$i-1]
    # for this result we calculate the modulo of the result with the greater value %$a[$i]
    # if the difference and the modulo are both even or odd this belongs to true
# and the modulo of the result must be greater as the sum of these before
    # Ask me not why I have make try and error in an excel sheet till I see this relation
||
(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0 # or differce modulator is even and difference $a[$i],$a[$i-1] is a multiple of half difference $a[$i-1],$a[$i-2] 
||
in_array($m,$w) # if the modulo result is equal to the values that we have check till this moment in the array we can also neglect the comparison
)
?:$t=0; # other cases belongs to false
echo$t; #Output

ดูเหมือนว่าสิ่งที่ฉันได้เห็นตารางมีค่าจาก [1,2,3,4,5,6] และฉันเปลี่ยนเฉพาะรายการสุดท้ายจนถึง 9 สำหรับ 2to3 และ 4to5 เราสร้างมูลค่าของค่าที่ต่ำกว่าใน การคำนวณแบบโมดูโล

table{width:95%;}th,td{border:1px solid}
<table><tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>35</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>2</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>7</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>45</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>3</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>3</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>8</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>55</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>7</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>4</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>9</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>65</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>2</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td></tr></table>


ทำไมคุณถึงแยก", "เมื่อคุณสามารถแยก","; ทำไมคุณถึงแยกเมื่อคุณสามารถทำรายการ ทำไมคุณถึงจัดเรียงเมื่อคุณสามารถใช้รายการเรียงลำดับได้? (ฉันยังไม่แน่ใจว่าวิธีการที่คุณใช้นั้นผิดพลาดหรือไม่คุณมีข้อพิสูจน์เพราะวรรณกรรมที่ฉันอ่านผ่านดูเหมือนจะแนะนำว่ามันยากกว่าสิ่งที่ฉันคิดว่ารหัสของคุณกำลังทำอยู่)
Jonathan Allan

@ JörgHülsermannขออภัยหากฉันเกิดความสับสนแม้ว่ามันจะแตกต่างกันก่อนที่คุณจะสามารถใช้รายการที่เรียงลำดับได้หากคุณเลือก
ข้าวสาลีตัวช่วยสร้าง

ฉันเกรงว่าฉันคิดว่าคุณจะต้องทดสอบมากกว่าแค่ mod 2 กับความแตกต่างเพราะตัวอย่าง[1,2,5,11,17]เป็นบัญญัติ อาจมีการดูกระดาษเชื่อมโยงในคำตอบของฉัน
Jonathan Allan

... และเพื่อยืนยันด้วยรหัสของผู้ค้นมากกว่าภูมิใจ: ideone.com/C022x0
Jonathan Allan

@WheatWizard คือ [1,2,5,11,17] จริงหรือเท็จ?
JörgHülsermann

4

JavaScript (ES6), 116 125 130

l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

สิ่งนี้ต้องการอาร์เรย์อินพุตที่เรียงลำดับจากมากไปน้อย สำหรับแต่ละค่าตั้งแต่ 2N ถึง 2 (N เป็นค่าสูงสุดของเหรียญ) จะค้นหาจำนวนเหรียญจากอัลกอริทึมโลภและพยายามหาชุดเหรียญที่มีขนาดเล็กลง

น้อย golfed

l=>{
  // recursive function to to find a smaller set of coins
  // parameter k is the max coin limit
  r = (d,k) => d // check if difference is not 0
     ? --k // if not, and if the number of coins used will be less than limit
      && l.map(v => v>d || r(d-v, k))  // proceed with the recursive search
     : x=1 // if diff is 0, value found, set x to 1 to stop the loop
  for( x=l[0]*2; --x > 1; )  
    g=0, h=x, l.map(v=>(g += h/v|0, h %= v)), // find g with the greedy algorithm
    r(x,g) // call with initial difference equal to target value
  return x
}

ทดสอบ

f=
l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

/* No eval
f=l=>{
  r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;
  for(x=l[0]*2;--x>1;r(x,g))
    g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));
  return x;
}*/

;[
 [[100,50,20,10,5,2,1],1], [[4,3,1],0],
 [[25,10,5,1],1], [[25,10,6,1],0],
 [[3,2,1],1], [[30,17,8,1], 0], 
 [[12,8,3,1],0], [[13,8,2,1], 0]
].forEach(t=>{
  var i=t[0],k=t[1],r=f(i),
      msg=((r==k)?'OK ':'KO ')+i+' -> '+r
      + (r==k?'':' (should be '+k+')')
  O.textContent += msg+'\n'
})

function test()
{
  var i=I.value.match(/\d+/g).map(x=>+x).sort((a,b)=>b-a)
  O.textContent = i+' -> '+f(i)+'\n'+O.textContent
 }
#I { width:50% }
<input id=I value='1 4 9'><button onclick='test()'>test</button>
<pre id=O></pre>


4

Python, 218 211 205 ไบต์

-1 ไบต์ขอบคุณ @TuukkaX (สามารถลบช่องว่างระหว่าง<3และor)

from itertools import*
g=lambda x,c,n=0:x and g(x-[v for v in c if v<=x][0],c,n+1)or n
lambda c:len(c)<3or 1-any(any(any(x==sum(p)for p in combinations(c*i,i))for i in range(g(x,c)))for x in range(c[0]*2))

repl.it

ป้อนตามลำดับจากมากไปน้อย

กำลังดุร้ายอย่างน่ากลัว ชุดของเหรียญหน่วยเดียวและเหรียญอื่น ๆ บางอย่างเป็นที่ยอมรับ สำหรับชุดที่มีขนาดใหญ่ที่มีขนาดเล็กล้มเหลวในกรณีถ้ามีจะสูงกว่าหรือเท่ากับเหรียญที่เล็กที่สุดที่ 3 (ไม่แน่ใจตัวเองว่ามันอาจจะเท่ากับ!) และน้อยกว่าผลรวมของทั้งสองเหรียญที่ใหญ่ที่สุด - ดูบทความนี้ (ซึ่งอันที่จริง การอ้างอิงอื่น แต่ให้เมธอด O (n ^ 3) ด้วย

g นับเหรียญที่ใช้โดยวิธีโลภและฟังก์ชั่นที่ไม่มีชื่อจะทำการส่งผู้สมัครที่เป็นไปได้ (จริง ๆ แล้วจาก 0 ถึงหนึ่งน้อยกว่าสองเท่าของเหรียญที่ใหญ่ที่สุดเพื่อบันทึกไบต์) และค้นหาการสะสมของเหรียญที่น้อยลง

gทำงานโดยการดำเนินการในสิ่งที่แคชเชียร์จะมันซ้ำเตะเหรียญที่ใหญ่ที่สุดน้อยกว่าหรือเท่ากับจำนวนเงินที่ยังคงที่จะทำให้ขึ้นไปและนับจำนวนของเหรียญที่ใช้[v for v in c if v<=x][0]n

ฟังก์ชั่นที่ไม่มีชื่อส่งคืน 1 ถ้าlen(c)น้อยกว่า 3 และมิฉะนั้นทดสอบว่ามันไม่ใช่ในกรณี1-...ที่ค่าใด ๆ ในช่วงของความเป็นไปได้range(c[0]*2)))มีความเป็นไปได้ที่จะมีเหรียญน้อยลงi in range(g(x,c))โดยทำการสะสมเหรียญจำนวนมากทุกเหรียญc*iและตรวจสอบiเหรียญcombinations(c*i,i)ทั้งหมดเพื่อดูว่าผลรวมใด ๆ ที่มีค่าเท่ากันหรือไม่


@WheatWizard มันคืนค่าเท็จสำหรับ [13,8,2,1] - ฉันเพิ่มลงในเคสทดสอบ เพิ่มการชี้แจงว่าอินพุตอยู่ในลำดับจากมากไปน้อย
Jonathan Allan

1
3orควรทำงาน.
Yytsi

ขอบคุณ @TuukkaX ฉันสามารถแทนที่not(...)ด้วย1-...
Jonathan Allan

2

เยลลี่ ( ส้อม ) 15 14 ไบต์

SRæFµS€Ṃ=$Ṫµ€Ȧ

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

โปรแกรมนี้คำนวณกรณีทดสอบทั้งหมดในเวลาไม่ถึงวินาทีบนเครื่องของฉัน

โชคไม่ดีนี่ขึ้นอยู่กับสาขาของ Jelly ที่ฉันทำงานเกี่ยวกับการใช้อะตอมของ Frobenius แก้ปัญหาดังนั้นคุณจึงไม่สามารถลองออนไลน์ได้

การใช้

$ ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ' '1,2,4,6,8'
1

ประสิทธิภาพดีและสามารถแก้ปัญหากรณีทดสอบทั้งหมดในครั้งเดียวในเวลาน้อยกว่าหนึ่งวินาที

$ time ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ¶Ç€' '[[1,3,4],[1,5,10,25],[1,6,10,25],[1,2,3],[1,8,17,30],[1,3,8,12],[1,2,8,13],[1,2,4,6,8]]'
[0, 1, 0, 1, 0, 0, 0, 1]

real    0m0.793s
user    0m0.748s
sys     0m0.045s

คำอธิบาย

SRæFµS€Ṃ=$Ṫµ€Ȧ  Input: list of integers C
    µ           Start a new monadic chain
S                 Sum
 R                Range, [1, 2, ..., sum(C)]
  æF              Frobenius solve for each X in the range using coefficients from C
                  This generates all vectors where the dot product of a
                  vector with C equals X, ordered by using values from the
                  start to end of C
           µ€   Start a new monadic chain that operates on each list of vectors
     S€           Sum each vector
         $        Monadic hook on the sums
       Ṃ            Minimum (This is the optimal solution)
        =           Vectorized equals, 1 if true else 0
          Ṫ       Tail (This is at the index of the greedy solution)
             Ȧ  All, returns 0 if it contains a falsey value, else 1

2

JavaScript (ES6), 144 132 124 122 110 ไบต์

a=>![...Array(a[0]*2)].some((_,i)=>(g=(a,l=0,n=i)=>[a.filter(c=>c>n||(l+=n/c|0,n%=c,0)),-l*!n])(...g(a))[1]>0)

ต้องการอาร์เรย์ที่จะเรียงลำดับจากมากไปน้อย ใช้การสังเกตในกระดาษที่เชื่อมโยงว่าหากระบบไม่ใช่บัญญัติซึ่งมีค่าอย่างน้อยหนึ่งค่าน้อยกว่า 2a [0] ซึ่งใช้เหรียญน้อยลงเมื่อย่อยสลายโดยใช้เหรียญที่ไม่ได้ใช้จากอัลกอริทึมโลภเริ่มต้น

แก้ไข: บันทึก 12 ไบต์โดยตระหนักว่าฉันสามารถตรวจสอบเหรียญทั้งหมดแม้ว่าฉันได้มาถึงมูลค่าเป้าหมายแล้ว บันทึก 8 ไบต์ด้วยการสลับเอาต์พุตกลางของฉันจาก[l,b]เป็น[b,-l]; สิ่งนี้ทำให้ฉันสามารถส่งผลลัพธ์แรกโดยตรงเป็นพารามิเตอร์ของการโทรที่สองบวกกับการประหยัดเล็กน้อยที่ตรวจพบว่าการโทรที่สองนั้นประสบความสำเร็จ บันทึก 2 ไบต์ด้วยการย้ายคำจำกัดความgไปยังการsomeเรียกกลับทำให้ฉันหลีกเลี่ยงการส่งผ่านตัวแปรลูปสองครั้งโดยไม่จำเป็น บันทึก 12 ไบต์ด้วยการสลับจากฟังก์ชั่นตัวช่วยเรียกซ้ำเพื่อเรียกไปยังfilter(ทำโดยสวิตช์เอาท์พุทระดับกลางของฉัน)


2

Perl, 69 ไบต์

รวมถึง +2 สำหรับ -pa

ให้เหรียญเรียงลำดับจากมากไปน้อยใน STDIN คุณสามารถเลือกที่จะละทิ้ง1เหรียญได้

coins.pl <<< "4 3 1"

coins.pl:

#!/usr/bin/perl -pa
$_=!map{grep$`>=$_&&($n=$G[$`-$_]+1)<($G[$`]||=$n),@F,/$/}1..2*"@F"

สร้างจำนวนเหรียญที่ใช้โดยอัลกอริทึมแคชเชียร์ใน@Gจำนวน 1 ถึงสองเหรียญที่ใหญ่ที่สุด สำหรับแต่ละจำนวนตรวจสอบว่าถ้าจำนวนเงินนั้นลดลงตามมูลค่า 1 เหรียญขั้นตอนวิธีพนักงานเก็บเงินต้องน้อยกว่า 1 เหรียญ หากไม่ใช่นี่คือตัวอย่างตัวอย่าง (หรือมีตัวอย่างก่อนหน้านี้) ฉันสามารถหยุดที่ตัวอย่างแรกได้ แต่ใช้เวลามากขึ้น ดังนั้นเวลาจึงซับซ้อนO(max_coin * coins)และซับซ้อนของพื้นที่O(max_coin)

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