Chuyển đổi một vấn đề về chiếc ba lô bị ràng buộc thành vấn đề về chiếc ba lô 0/1


12

Tôi đã gặp một vấn đề trong đó mục tiêu là sử dụng lập trình động (thay vì các phương pháp khác). Có một khoảng cách được kéo dài và một bộ dây cáp có độ dài khác nhau. Số lượng cáp tối thiểu cần thiết để kéo dài khoảng cách chính xác là gì?

Đối với tôi điều này trông giống như một vấn đề về chiếc ba lô , nhưng vì có thể có bội số của một độ dài cụ thể, đó là một vấn đề về chiếc ba lô bị ràng buộc, thay vì vấn đề về chiếc ba lô 0/1. (Coi giá trị của mỗi vật phẩm là trọng lượng của nó.) Sử dụng cách tiếp cận ngây thơ (và không quan tâm đến việc mở rộng không gian tìm kiếm), phương pháp tôi đã sử dụng để chuyển đổi vấn đề về chiếc ba lô bị ràng buộc thành vấn đề về chiếc ba lô 0/1, chỉ đơn giản là chia các bội số thành đơn và áp dụng thuật toán lập trình động nổi tiếng. Thật không may, điều này dẫn đến kết quả không tối ưu.

Ví dụ: cáp đã cho:
1 x 10ft,
1 x 7ft,
1 x 6ft,
5 x 3ft,
6 x 2ft,
7 x 1ft

Nếu khoảng mục tiêu là 13ft, thuật toán DP chọn 7 + 6 để kéo dài khoảng cách. Một thuật toán tham lam sẽ chọn 10 + 3, nhưng đó là một ràng buộc cho số lượng cáp tối thiểu. Vấn đề phát sinh, khi cố gắng kéo dài 15ft. Thuật toán DP đã kết thúc chọn 6 + 3 + 3 + 3 để có 4 cáp, trong khi thuật toán tham lam chọn chính xác 10 + 3 + 2 chỉ cho 3 cáp.

Dù sao, thực hiện một số quét ánh sáng chuyển đổi giới hạn thành 0/1, có vẻ như cách tiếp cận nổi tiếng để chuyển đổi nhiều mục thành {p, 2p, 4p ...}. Câu hỏi của tôi là làm thế nào để chuyển đổi này hoạt động nếu p + 2p + 4p không thêm vào số lượng nhiều mục. Ví dụ: Tôi có 5 cáp 3ft. Tôi không thể thêm {3, 2x3, 4x3} vì 3 + 2x3 + 4x3> 5x3. Tôi có nên thêm {3, 4x3} không?

[Tôi hiện đang cố gắng tìm hiểu bài báo "Vấn đề Knapsack Oregon Trail", nhưng hiện tại có vẻ như cách tiếp cận được sử dụng không có lập trình động.]


1
Tôi nghĩ rằng điều này phù hợp hơn với math.stackexchange.com hoặc thậm chí mathoverflow.net
Oded

3
Tôi đã bị giằng xé giữa dòng stackoverflow, và ở đây. Đọc Câu hỏi thường gặp trên cả hai trang web, trang web này liệt kê các cấu trúc dữ liệu và thuật toán trước tiên. Đọc FAQ cho trang web toán học, có vẻ như đề nghị hỏi tại trang web cstheory thay thế.
Kiến

Câu trả lời:


1

Nó có thể là một số sai lầm trong mã của bạn. Tôi đã viết chương trình DP như được đề cập bởi Naryshkin. Đối với nhịp mục tiêu 13, nó báo cáo 6 + 7 và cho 15, nó báo cáo 2 + 6 + 7.

# weight: cable length
# total weight: target span
# value: 1 for each cable
# want minimum number of cables, i.e. minimum total value

def knapsack_01_exact_min(weights, values, W):
    # 0-1 knapsack, exact total weight W, minimizing total value
    n = len(weights)
    values = [0] + values
    weights = [0] + weights
    K = [[0 for i in range(W+1)] for j in range(n+1)]
    choice = [[0 for i in range(W+1)] for j in range(n+1)]
    for i in range(1, n+1):
        for w in range(1, W+1):
            K[i][w] = K[i-1][w]
            choice[i][w] = '|'
            if w >= weights[i]:
                t = K[i-1][w-weights[i]]
                if (w==weights[i] or t) and (K[i][w]==0 or t+values[i] < K[i][w]):
                    choice[i][w] = '\\'
                    K[i][w] = t+values[i]
    return K[n][W], choice

def print_choice(choice, weights):
    i = len(choice)-1
    j = len(choice[0])-1
    weights = [0] + weights
    while i > 0 and j > 0:
        if choice[i][j]=='\\':
            print weights[i],
            j -= weights[i]
        i -= 1
    print

lens = [10, 7, 6] + 5*[3] + 6*[2] + 7*[1]
values = (3+5+6+7)*[1]
span = 13
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

span = 15
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

Nếu bạn điều chỉnh thứ tự độ dài đầu vào, nó có thể đưa ra các giải pháp tối ưu khác. Ví dụ: lens = 5*[3] + 6*[2] + 7*[1] + [10, 7, 6]sẽ cho 15 = 10 + 2 + 3.


Nơi bạn đã nhận được câu lệnh if: 'if (w-weights [i] == 0 hoặc t) và (K [i] [w] == 0 hoặc t + value [i] <K [i] [w] ): '? Nếu bây giờ quên nguồn thuật toán DP của tôi, nhưng tôi không có kiểm tra 0, chỉ kiểm tra '(t + value [i] <K [i] [w])'
Ants

1
Bạn đang giải quyết cho tổng trọng lượng chính xác , điều đó có nghĩa là bất cứ khi nào một mục được chọn, chúng tôi cần đảm bảo trọng lượng chính xác (của bước hiện tại) được đáp ứng. Vì vậy, khi chúng tôi quyết định chọn một mục, mệnh đề thứ hai "t + value [i] <K [i] [w]" đảm bảo chúng tôi sẽ có tổng giá trị nhỏ hơn; nhưng trước đó, chúng ta cũng cần phải lấp đầy trọng lượng cần thiết, tức là các mục i-1 đầu tiên phải có thể lấp đầy trọng lượng (w-weights [i]), do đó là mệnh đề đầu tiên "if K [i-1] [w -weights [i]] "(Tôi đang sử dụng biến t tạm thời cho điều đó).
jsz

Có hai kiểm tra bổ sung "w == trọng số [i]" và "K [i] [w] == 0"; chúng là cần thiết và do cách các bảng được khởi tạo; Tôi nghĩ bạn sẽ có thể làm được vì vậy tôi sẽ không đi sâu vào chi tiết. (Tôi đã thay đổi trọng số w [i] == 0 thành w == trọng số [i]; cần rõ ràng hơn).
jsz

1

Cách mà tôi đã thấy được sử dụng để chuyển đổi một vấn đề về chiếc ba lô bị ràng buộc thành một cái 0/1 là chỉ có nhiều vật phẩm giống hệt nhau. Nói nếu bạn có các mục sau (được tính theo trọng lượng, tiện ích):

  • 2 x 1, 2
  • 3 x 2, 3

Bạn sẽ biến nó thành vấn đề 0/1 bằng cách sử dụng các mục với

  • 1, 2
  • 1, 2
  • 2, 3
  • 2, 3
  • 2, 3

Và sử dụng thuật toán 0/1 để giải nó. Bạn có thể sẽ có nhiều giải pháp có độ chính xác như nhau để bạn chọn một giải pháp tùy ý.


Bây giờ về vấn đề dây của bạn: Tôi sẽ có chiều dài của cáp là tầm nhìn và giá trị của mỗi cáp giống hệt nhau (gọi nó là 1, mặc dù mọi giá trị dương sẽ hoạt động). Bây giờ, sử dụng thuật toán giải Knapsack yêu thích của bạn nhưng ở đó bạn thường chọn giải pháp (một phần) tối đa hóa giá trị, chọn một giải pháp tối thiểu hóa nó. Ngoài ra, bỏ qua tất cả các giải pháp không có tổng trọng số tương đương với công suất. Tôi có thể (cố gắng) viết một thuật toán cụ thể hơn với mã thực tế nếu có ai muốn nó.


Yup, đó chính xác là những gì tôi làm để điền vào trọng lượng và giá trị. Tôi đã tính toán cho giá trị tối đa, thay vì tối thiểu. Bây giờ tôi vừa thay đổi mã để tính toán cho min như bạn đề xuất và khởi tạo hàng 0 của bảng DP thành MAXINT. Vẫn là kết quả tương tự, giải pháp lập trình động cho các vấn đề về chiếc ba lô vẫn kết thúc bằng cách chọn 6 + 3 + 3 + 3 thay vì 10 + 3 + 2 hoặc 7 + 6 + 2.
Kiế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.