การแบ่งเงินดอลลาร์และการเปลี่ยนแปลงที่สมบูรณ์แบบ


11

ฉันมี $ 15 ในกระเป๋าของฉัน ฉันอยู่ในร้านที่ไม่เปลี่ยนแปลง ในขณะที่เรียกดูฉันพบรายการที่ราคา 10 ดอลลาร์ (รวมภาษี) ฉันสามารถซื้อของชิ้นนั้นได้โดยไม่เสียเงินหรือไม่?

ในกรณีนี้คำตอบคือใช่ ไม่ว่าเงิน $ 15 ของฉันจะถูกแบ่งเป็นอย่างไร (หนึ่ง 10 และหนึ่ง 5 หรือสาม 5s หรืออย่างอื่น) ฉันจะได้ $ 10 ที่แน่นอนเสมอ

เป็นตัวอย่างที่สองฉันมี $ 0.16 ในกระเป๋าของฉัน ฉันต้องจ่ายเงินเป็นจำนวนเท่าใด?

Possible Divisions:
0.01, 0.05, 0.10
0.01, 0.05 x 3
0.01 x 16
Guaranteed Exact Change:
0.01, 0.05, 0.06, 0.10, 0.11, 0.15, 0.16

จะทำอย่างไรถ้าฉันมี $ 0.27 ในกระเป๋าของฉัน

Possible Divisions:
0.01 x 2, 0.25
0.01 x 2, 0.05, 0.10 x 2
0.01 x 2, 0.05 x 3, 0.10
0.01 x 2, 0.05 x 5
0.01 x 27
Guaranteed Exact Change:
0.01, 0.02, 0.25, 0.26, 0.27

ในกรณีข้างต้นมีเพียงไม่กี่เงินที่ฉันจะเปลี่ยนแปลงได้อย่างสมบูรณ์แบบเสมอ

งานของคุณ

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

อาจเป็นคำอธิบายที่ละเอียดมากขึ้น

ฉันมีเงินจำนวนหนึ่งอยู่ในกระเป๋าของฉันซึ่งเกิดขึ้นจากการสาธิตของสกุลเงินที่เป็นไปได้ หากฉันมี 8 ดอลลาร์และฉันรู้ว่าสกุลเงินที่เป็นไปได้คือ $ 2 และ $ 3 นั่นก็คือมีตั๋วหลายใบที่รวมอยู่ในกระเป๋าของฉัน เหล่านี้คือ2+2+2+23+3+2และ เพื่อให้สามารถผลิตจำนวนเงินที่แน่นอนฉันต้องสามารถผลิตจำนวนนั้นโดยใช้ตั๋วเงินที่มีอยู่ในกระเป๋าของฉันเท่านั้น ถ้าฉันมีสี่ 2 วินาทีฉันก็สามารถผลิต2, 4, 6, or 8ได้ ถ้าฉันมีสอง 3s และ 2 ผมสามารถผลิต2, 3, 5, 6, or 8ตั้งแต่ผมไม่ทราบว่าของชุดเหล่านี้ที่จริงผมมีในกระเป๋าของฉัน, 2, 6, 8คำตอบสุดท้ายของฉันจะลดลงไป เหล่านี้คือค่าที่ฉันรู้ว่าฉันสามารถผลิตได้จากกระเป๋าของฉันกำหนดจำนวนเงินทั้งหมดและราคาที่เป็นไปได้

ตัวอย่าง I / O จากการคำนวณด้วยมือ

7 [3, 4]
3, 4, 7        //only one possible division into 3 + 4

7 [3, 2]
2, 3, 4, 5, 7  //the only division is 3 + 2 + 2

6 [2, 3, 4]
6     //divisions are 2+2+2, 3+3, 2+4 

16 [1, 5, 10, 25]          //this represents one of the examples above
1, 5, 6, 10, 11, 15, 16

27 [1, 5, 10, 25]          //another example from above
1, 2, 25, 26, 27

1500 [1, 5, 10, 25, 100, 500, 1000, 2000]
500, 1000, 1500

600 [100, 500, 1000, 2000]
100, 500, 600

600 [200, 1, 5, 10, 25, 100, 500, 1000, 2000]
600

มันไม่ชัดเจนมาก
motoku

@FryAmTheEggman ฉันได้เพิ่ม "อาจเป็นคำอธิบายที่ละเอียดยิ่งขึ้น" แจ้งให้เราทราบหากยังคงสับสน (ฉันลบกรณีขอบออกเพราะมันไม่มีประโยชน์อะไรมาก)
PhiNotPi

6 [2, 3, 4]ฉันไม่เห็นวิธีการที่คุณจะได้รับ ไม่สามารถ2+2+2สร้าง 3 และ3+3ไม่สร้าง 2 และ 4 ได้หรือไม่
xnor

@ xnor คุณถูกต้องแก้ไข
PhiNotPi

โปรแกรมควรรันในเวลาที่เหมาะสมสำหรับอินพุตทั้งหมดหรือไม่ เช่นความคิดที่สั้นที่สุดของฉันคือเลขชี้กำลังในจำนวนเริ่มต้นและ 2 ^ 1500 เป็นจำนวนมาก
randomra

คำตอบ:


2

Python 2, 200 197 193 140 ไบต์

f=lambda n,D,S={0}:sum([f(n-x,D,S|{x+y for y in S})for x in D],[])if n>0else[S]*-~n
g=lambda*a:(f(*a)and reduce(set.__and__,f(*a))or{0})-{0}

(ขอบคุณ @Nabb สำหรับเคล็ดลับ)

นี่เป็นวิธีแก้ปัญหาที่ไม่ดีนักสำหรับตอนนี้เพื่อเริ่มต้นสิ่งต่าง ๆ Call with g(16, [1, 5, 10, 25])- output เป็นชุดที่เกี่ยวข้องกับนิกาย

วิธีการตรงไปตรงมาและแบ่งออกเป็นสองขั้นตอน:

  • fดูทุกวิธีในการเข้าถึงnด้วยนิกายD(เช่น[1, 5, 10]) และสำหรับแต่ละอันมันจะคำนวณจำนวนเงินทั้งหมดที่สามารถทำได้ด้วยนิกายเหล่านี้ (เช่นset([0, 1, 5, 6, 10, 11, 15, 16]))
  • gคำนวณค่าตัดของผลลัพธ์ของfจากนั้นลบ 0 สำหรับคำตอบสุดท้าย

โปรแกรมแก้ปัญหากรณีที่ 1-5 และ 7 ปรับสแต็คล้นในวันที่ 6 และใช้เวลาตลอดไปในวันที่ 8

หากไม่มีวิธีแก้ปัญหา (เช่นg(7, [2, 4, 6])) จากนั้นโปรแกรมจะส่งคืนชุดว่าง หากได้รับอนุญาตให้โยนข้อผิดพลาดสำหรับกรณีเช่นนี้แสดงว่าสั้นกว่าg:

g=lambda*a:reduce(set.__and__,f(*a))-{0}

g=lambda L,c=0:L and g(L[1:],c)|g(L,c+L.pop(0))or{c}สั้นไปหน่อย
Nabb

เพิ่มขึ้นอีกนิดโดยการย้าย-{0}เข้าสู่กรัมและใช้[L]*-~nแทน[L][-n:]
Nabb

1

JavaScript (ES6) 162 203 207

แก้ไขเปลี่ยนวิธีการตัดชุดผลลัพธ์ในอาร์เรย์ r เร็วขึ้นเล็กน้อย แต่อัลกอริทึมยังคงเหม็นอยู่

คำอธิบายรายละเอียดเพิ่มเติมจะตามมา
ไม่นาน: c เป็นฟังก์ชันแบบเรียกซ้ำที่ระบุส่วนย่อยที่เป็นไปได้ทั้งหมด k เป็นฟังก์ชันเรียกซ้ำที่ระบุจำนวนผลรวมทั้งหมดที่เป็นไปได้ ชุดผลลัพธ์ใหม่ใด ๆ ที่พบกับฟังก์ชั่น k จะถูกเปรียบเทียบกับชุดก่อนหน้านี้ที่พบเฉพาะผลลัพธ์ทั่วไปจะถูกเก็บไว้

ทำไมมันช้าจัง เมื่อต้องจัดการผลรวมเป้าหมาย, บอก, 1500 และชิ้นส่วนของค่า 1, การแจกแจงจำนวนเงินที่เป็นไปได้ทั้งหมดไม่ใช่ความคิดที่ดี

F=(s,d,r,
  c=(s,i,t=[],v,k=(i,s,v)=>{for(;v=t[i++];)k(i,s+v);o[s]=s})=>
  {for(s||(i=k(o=[],0),r=(r||o).filter(v=>o[v]));v=d[i];++i)s<v||c(s-v,i,[...t,v])}
)=>c(s,0)||r

Ungolfed

F=(s,d)=>{
  var r
  var c=(s,i,t=[])=>
  {
    var o=[],v
    var k=(i,s)=> // find all sums for the current list t, set a flag in the o array
    {
      var v
      for(;v=t[i++];)k(i,s+v)
      o[s]=s
    }

    if (s==0) {
      k(0,0)
      if (r)
        r = r.filter(v=>o[v]) // after first loop, intersect with current
      else
        r = o.filter(v=>v) // first loop, keep all results
    } 
    else
      for(;v=d[i];++i)
      { 
        if (s >= v) 
          c(s-v, i, t.concat(v))
      }
  }
  c(s,0) // enumerate all possible set of pieces
  return r
}

ทดสอบในคอนโซล Firefox / FireBug

F(16,[1,5,10,25])

[1, 5, 6, 10, 11, 15, 16]

(เวลา 84 มิลลิวินาที)

F(27, [1, 5, 10, 25]) 

[1, 2, 25, 26, 27]

(เวลา 147252 มิลลิวินาทีจึงไม่เร็วนัก)


0

Wolfram Methematica, 104 ไบต์

Rest@*Intersection@@Map[Total]/@Subsets/@Union[Sort/@IntegerPartitions[#,#,PadLeft[{},Length[#2]#,#2]]]&

Ungolfed (อ่านจากตอนท้าย):

Rest@* // Removing 0
  Intersection@@   // Intersecting all totals
     Map[Total]/@  // Counting total of each subset
        Subsets/@  // Getting all the subsets of each partition
           Union[  // Removing duplicates 
              Sort/@ // Sorting each partition (to remove duplicates next)
                 IntegerPartitions[#,#,PadLeft[{},Length[#2]#,#2]] // Getting all Integer partitions
                ]&
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.