Algorithm 无限整数数组上的0-1背包?
Algorithm 无限整数数组上的0-1背包?,algorithm,dynamic-programming,Algorithm,Dynamic Programming,给定一个无限正整数数组或一个正整数流,找出前五个和为20的数字。 通过阅读问题陈述,首先似乎是0-1背包问题,但我很困惑0-1背包算法能否用于整数流。假设我为上述问题编写了一个递归程序 int knapsack(int sum, int count, int idx) { if (sum == 0 && count == 0) return 1; if ((sum == 0 && count != 0) || (sum != 0
给定一个无限正整数数组或一个正整数流,找出前五个和为20的数字。
通过阅读问题陈述,首先似乎是0-1背包
问题,但我很困惑0-1背包算法能否用于整数流。假设我为上述问题编写了一个递归程序
int knapsack(int sum, int count, int idx)
{
if (sum == 0 && count == 0)
return 1;
if ((sum == 0 && count != 0) || (sum != 0 && count == 0))
return 0;
if (arr[idx] > 20) //element cann't be included.
return knapsack(sum, count idx + 1);
return max(knapsack(sum, count, idx +1), knapsack(sum - arr[idx], count -1, idx + 1));
}
现在,当上述函数调用无限数组时,max
函数中的第一个调用,即背包(sum,count,idx+1)
将永远不会返回,因为它将继续忽略当前元素。即使我们在max
函数中更改调用的顺序,仍然有可能第一次调用永远不会返回。在这种情况下,有什么方法可以应用背包算法吗?如果你只使用正整数,这是有效的
基本上保留一个列表,列出你可以达到前20个数字中的任何一个的方法,每当你处理一个新的数字时,相应地处理这个列表
def update(dictlist, num):
dk = dictlist.keys()
for i in dk:
if i+num <=20:
for j in dictlist[i]:
listlen = len(dictlist[i][j]) + 1
if listlen >5:
continue
if i+num not in dictlist or listlen not in dictlist[i+num]:
dictlist[i+num][listlen] = dictlist[i][j]+[num]
if num not in dictlist:
dictlist[num]= {}
dictlist[num][1] = [num]
return dictlist
dictlist = {}
for x in infinite_integer_stream:
dictlist = update(dictlist,x)
if 20 in dictlist and 5 in dictlist[20]:
print dictlist[20][5]
break
def更新(dictlist,num):
dk=dictlist.keys()
对于dk中的i:
如果i+num 5:
持续
如果i+num不在dictlist中或listlen不在dictlist中[i+num]:
dictlist[i+num][listlen]=dictlist[i][j]+[num]
如果num不在列表中:
dictlist[num]={}
dictlist[num][1]=[num]
返回目录
dictlist={}
对于无限多个整数流中的x:
dictlist=更新(dictlist,x)
如果听写列表中有20个,听写列表中有5个[20]:
打印目录[20][5]
打破
这段代码可能有一些小错误,我现在没有时间调试它。但基本上dictlist[i][j]存储一个j长度的列表,其总和为i。Delphi代码:
var
PossibleSums: array[1..4, 0..20] of Integer;
Value, i, j: Integer;
s: string;
begin
s := '';
for j := 1 to 4 do
for i := 0 to 20 do
PossibleSums[j, i] := -1;
while True do begin
Value := 1 + Random(20); // stream emulation
Memo1.Lines.Add(IntToStr(Value));
if PossibleSums[4, 20 - Value] <> -1 then begin
//we just have found 5th number to make the full sum
s := IntToStr(Value);
i := 20 - Value;
for j := 4 downto 1 do begin
//unwind storage chain
s := IntToStr(PossibleSums[j, i]) + ' ' + s;
i := i - PossibleSums[j, i];
end;
Memo1.Lines.Add(s);
Break;
end;
for j := 3 downto 1 do
for i := 0 to 20 - Value do
if (PossibleSums[j, i] <> -1) and (PossibleSums[j + 1, i + Value] = -1) then
PossibleSums[j + 1, i + Value] := Value;
if PossibleSums[1, Value] = -1 then
PossibleSums[1, Value] := Value;
end;
end;
你是在寻找前五个和为20的连续数字吗?这比背包问题更难。我们还有一个额外的限制:我们必须找到最早的数字组合,其和为20。换句话说,我们必须考虑多个背包:前5个元素,然后前6个,然后前7个,等等。”戴维:不。没有这样的条件…@cheeken如果整数是正的,你可以找到最早的组合。请看下面我的答案。@ElKamina:是的,整数是正的。。。我将更新这个问题。嗯,你在哪里施加5元素约束?@cheeken我错过了那部分。更新后的答案应该可以解决这个问题。
4
8
9
2
10
2
17
2
4 2 10 2 2