Đây là chi tiết của một giải pháp lai, với lập trình năng động và lại theo dõi. Chúng ta có thể sử dụng Back Tracking một mình để giải quyết vấn đề này, nhưng sau đó chúng ta phải tìm kiếm toàn bộ (2^N) để tìm ra giải pháp. Phần DP tối ưu hóa không gian tìm kiếm trong Theo dõi ngược.
import sys
from collections import OrderedDict
MinimumSum = 31
MaxArraySize = 4
InputData = sorted([1,4,5,10,17,34])
# Input part is over
Target = MinimumSum + 1
Previous, Current = OrderedDict({0:0}), OrderedDict({0:0})
for Number in InputData:
for CurrentNumber, Count in Previous.items():
if Number + CurrentNumber in Current:
Current[Number + CurrentNumber] = min(Current[Number + CurrentNumber], Count + 1)
else:
Current[Number + CurrentNumber] = Count + 1
Previous = Current.copy()
FoundSolution = False
for Number, Count in Previous.items():
if (Number >= Target and Count < MaxArraySize):
MaxArraySize = Count
Target = Number
FoundSolution = True
break
if not FoundSolution:
print "Not possible"
sys.exit(0)
else:
print Target, MaxArraySize
FoundSolution = False
Solution = []
def Backtrack(CurrentIndex, Sum, MaxArraySizeUsed):
global FoundSolution
if (MaxArraySizeUsed <= MaxArraySize and Sum == Target):
FoundSolution = True
return
if (CurrentIndex == len(InputData) or MaxArraySizeUsed > MaxArraySize or Sum > Target):
return
for i in range(CurrentIndex, len(InputData)):
Backtrack(i + 1, Sum, MaxArraySizeUsed)
if (FoundSolution): return
Backtrack(i + 1, Sum + InputData[i], MaxArraySizeUsed + 1)
if (FoundSolution):
Solution.append(InputData[i])
return
Backtrack(0, 0, 0)
print sorted(Solution)
Lưu ý: Theo các ví dụ được đưa ra bởi bạn trong câu hỏi, tổng tối thiểu và tối đa kích thước mảng là nghiêm chỉnh hơn và ít hơn các giá trị quy định, tương ứng.
Đối với đầu vào này
MinimumSum = 31
MaxArraySize = 4
InputData = sorted([1,4,5,10,17,34])
Output là
[5, 10, 17]
nơi như, ví đầu vào này
MinimumSum = 31
MaxArraySize = 3
InputData = sorted([1,4,5,10,17,34])
Output là
[34]
Giải thích
Target = MinimumSum + 1
Previous, Current = OrderedDict({0:0}), OrderedDict({0:0})
for Number in InputData:
for CurrentNumber, Count in Previous.items():
if Number + CurrentNumber in Current:
Current[Number + CurrentNumber] = min(Current[Number + CurrentNumber], Count + 1)
else:
Current[Number + CurrentNumber] = Count + 1
Previous = Current.copy()
Phần này của chương trình phát hiện số lượng tối thiểu các số từ dữ liệu đầu vào, yêu cầu thực hiện tổng số từ 1 đến số lượng tối đa có thể (đó là tổng của tất cả các dữ liệu đầu vào). Đó là một giải pháp lập trình năng động, cho vấn đề knapsack. Bạn có thể đọc về điều đó trên internet.
FoundSolution = False
for Number, Count in Previous.items():
if (Number >= Target and Count < MaxArraySize):
MaxArraySize = Count
Target = Number
FoundSolution = True
break
if not FoundSolution:
print "Not possible"
sys.exit(0)
else:
print Target, MaxArraySize
Phần này của chương trình, tìm giá trị Target
khớp với tiêu chí MaxArraySize
.
def Backtrack(CurrentIndex, Sum, MaxArraySizeUsed):
global FoundSolution
if (MaxArraySizeUsed <= MaxArraySize and Sum == Target):
FoundSolution = True
return
if (CurrentIndex == len(InputData) or MaxArraySizeUsed > MaxArraySize or Sum > Target):
return
for i in range(CurrentIndex, len(InputData)):
Backtrack(i + 1, Sum, MaxArraySizeUsed)
if (FoundSolution): return
Backtrack(i + 1, Sum + InputData[i], MaxArraySizeUsed + 1)
if (FoundSolution):
Solution.append(InputData[i])
return
Backtrack(0, 0, 0)
Bây giờ chúng ta biết rằng giải pháp tồn tại, chúng tôi muốn tạo lại giải pháp. Chúng tôi sử dụng kỹ thuật backtracking tại đây. Bạn có thể dễ dàng tìm thấy rất nhiều hướng dẫn tốt về điều này cũng trên internet.
Nếu bạn muốn giới hạn kích thước mảng thành 5 và tổng cộng 37 nếu danh sách là '[1,4,5,10,17,37]', bạn có muốn nó trả về '[37]' hay ' [1,4,5,10,17] '? – lurker
Điều này trông giống như một biến thể trên http://en.wikipedia.org/wiki/Knapsack_problem –
@mbratch: Nó sẽ trả lại 37. – crough