Chia hết đô la và thay đổi hoàn hảo


11

Tôi có 15 đô la trong túi của tôi. Tương tự như vậy, tôi đang ở trong một cửa hàng không thay đổi. Trong khi duyệt, tôi phát hiện ra một mặt hàng có giá $ 10 (đã bao gồm thuế). Tôi có thể mua món đồ đó mà không mất tiền không?

Trong trường hợp này, câu trả lời là có. Bất kể 15 đô la của tôi được chia như thế nào (một 10 và một 5, hoặc ba 5s, hoặc một cái gì khác), tôi sẽ luôn có chính xác 10 đô la cần thiết.

Lấy ví dụ thứ hai, tôi có 0,16 đô la trong túi. Những khoản tiền nào khác tôi phải có thể trả chính xác?

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

Nếu tôi có 0,27 đô la trong túi thì sao?

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

Trong trường hợp trên, chỉ có một vài khoản tiền mà tôi sẽ luôn có sự thay đổi hoàn hảo.

Nhiệm vụ của bạn

Viết chương trình ngắn nhất (hoặc hàm được đặt tên) trong đó lấy A) một số tiền nguyên và B) một danh sách các mệnh giá có thể làm đầu vào và đưa ra danh sách các khoản tiền mà tôi phải có sự thay đổi hoàn hảo. Đầu vào có thể là STDIN hoặc đối số cho chương trình hoặc hàm. Tôi sẽ không quá nghiêm ngặt về định dạng đầu vào; nó có thể phù hợp với cách định dạng ngôn ngữ của bạn mảng.

Có lẽ một lời giải thích chi tiết hơn

Tôi có một số tiền nhất định trong túi của mình, được hình thành từ một tập hợp các minh chứng có thể có về tiền tệ. Nếu tôi có 8 đô la và tôi biết rằng các mệnh giá có thể là 2 đô la và 3 đô la, thì chỉ có rất nhiều tổ hợp hóa đơn khác nhau có thể có trong túi của tôi. Đây là 2+2+2+23+3+2. Để có thể tạo ra một số tiền chính xác, tôi phải có khả năng sản xuất số lượng đó bằng cách sử dụng các hóa đơn duy nhất trong túi của mình. Nếu tôi có bốn 2 giây, tôi có thể sản xuất 2, 4, 6, or 8. Nếu tôi có hai số 3 và số 2, tôi có thể sản xuất 2, 3, 5, 6, or 8Vì tôi không biết những kết hợp nào tôi thực sự có trong túi, câu trả lời cuối cùng của tôi bị giảm xuống 2, 6, 8. Đây là những giá trị tôi biết tôi có thể tạo ra từ túi của mình, với tổng số tiền và các mệnh giá có thể.

Ví dụ tính toán 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

Điều này rất không rõ ràng.
motoku

@FryAmTheEggman Tôi đã thêm một "có lẽ là một lời giải thích chi tiết hơn." Hãy cho tôi biết nếu nó vẫn còn khó hiểu. (Tôi cũng đã loại bỏ một trường hợp cạnh vì nó khá vô nghĩa.)
PhiNotPi

Tôi không thấy cách bạn nhận được 6 [2, 3, 4]. Không thể 2+2+2tạo 3 và 3+3không tạo 2 và 4?
xnor 27/2/2015

@xnor bạn đúng, đã sửa.
PhiNotPi 27/2/2015

Chương trình nên chạy trong thời gian hợp lý cho tất cả các đầu vào? Ví dụ, ý tưởng ngắn nhất của tôi là theo cấp số nhân trong số tiền bắt đầu và 2 ^ 1500 là rất nhiều thứ.
Randomra

Câu trả lời:


2

Python 2, 200 197 193 140 byte

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}

(Cảm ơn @Nabb về các mẹo)

Bây giờ đây là một giải pháp chơi golf kém để bắt đầu mọi thứ. Gọi với g(16, [1, 5, 10, 25])- đầu ra là một tập hợp với các mệnh giá liên quan.

Cách tiếp cận rất đơn giản và được chia thành hai bước:

  • fxem xét tất cả các cách tiếp cận nvới các mệnh giá D(ví dụ [1, 5, 10]), và đối với mỗi cách, nó thực hiện tất cả các số tiền có thể được thực hiện với các mệnh giá này (ví dụ set([0, 1, 5, 6, 10, 11, 15, 16])).
  • gtính toán các giao điểm của kết quả f, sau đó xóa 0 cho câu trả lời cuối cùng.

Chương trình giải quyết các trường hợp 1-5 và 7 tiền phạt, chồng tràn vào ngày 6 và mất mãi mãi vào ngày 8.

Nếu không có giải pháp (ví dụ g(7, [2, 4, 6])), thì chương trình trả về một tập hợp trống. Nếu một lỗi được phép ném cho trường hợp như vậy, thì đây là một lỗi ngắn hơn 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}ngắn hơn một chút
Nabb

Thêm một chút nữa bằng cách chuyển -{0}sang g và sử dụng [L]*-~nthay vì[L][-n:]
Nabb

1

JavaScript (ES6) 162 203 207

Chỉnh sửa Thay đổi cách để giao các tập kết quả trong mảng r. Nhanh hơn một chút, nhưng thuật toán vẫn bốc mùi.

Giải thích chi tiết hơn sẽ làm theo.
Tóm lại: c là một hàm đệ quy liệt kê tất cả các phân ngành có thể. k là một hàm đệ quy liệt kê tất cả các khoản tiền có thể có mà không lặp lại. Bất kỳ tập kết quả mới nào được tìm thấy với hàm k được so sánh với tập trước đó được tìm thấy, chỉ có các kết quả chung được giữ.

Tại sao nó lại chậm như vậy? Phải quản lý tổng số mục tiêu là 1500 và một phần giá trị 1, liệt kê tất cả các khoản tiền sở hữu không phải là một ý tưởng hay.

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

Ung dung

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
}

Kiểm tra trong bảng điều khiển Firefox / FireBug

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

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

(thời gian 84 phút)

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

[1, 2, 25, 26, 27]

(thời gian 147252 msec, vì vậy không quá nhanh)


0

Wolfram Methematica, 104 byte

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

Ungolfed (đọc từ cuối):

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
                ]&
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.