Algorithm 函数查找加起来等于某个值的X个数字

Algorithm 函数查找加起来等于某个值的X个数字,algorithm,lua,Algorithm,Lua,我需要一个函数来查找数量可变的数字,这些数字加起来必须等于某个值。在这种情况下是8 可以加在一起的数字在表中预定义,以使事情更简单。 当前的方法是:使用一个小算法洗牌表,将前X个值加在一起,如果它们加起来不等于8,则重新开始(包括再次洗牌),直到前X个值加起来等于8 我的代码确实有效,但有两个问题:处理它需要很长时间(显然),如果我不添加冷却时间,它可能会导致堆栈溢出错误 代码可能是脏的,它不是用于实时生产的。而且我充其量只是一个中级lua开发人员 function sleep (a) -- r

我需要一个函数来查找数量可变的数字,这些数字加起来必须等于某个值。在这种情况下是8

可以加在一起的数字在表中预定义,以使事情更简单。 当前的方法是:使用一个小算法洗牌表,将前X个值加在一起,如果它们加起来不等于8,则重新开始(包括再次洗牌),直到前X个值加起来等于8

我的代码确实有效,但有两个问题:处理它需要很长时间(显然),如果我不添加冷却时间,它可能会导致堆栈溢出错误

代码可能是脏的,它不是用于实时生产的。而且我充其量只是一个中级lua开发人员

function sleep (a) -- random sleep function I found
    local sec = tonumber(os.clock() + a); 
    while (os.clock() < sec) do 
    end 
end

function shuffle(tbl) -- random shuffle function I found
  for i = #tbl, 2, -1 do
    math.randomseed( os.time() )
    math.random();math.random();math.random();math.random();
    local j = math.random(i)
    tbl[i], tbl[j] = tbl[j], tbl[i]
  end
  return tbl
end

local times = {
    0.5,
    1.0,
    1.5,
    2.0,
    2.5,
    3.0,
    3.5,
    4.0
}


local timeunits = {} --refer to line 49, I did not want to do it like that...

function nnumbersto8(amount)

    local sum = 0
    local numbs = {}

    times = shuffle(times) --reshuffle the set

    for i = 1,amount,1 do --add first x values together
        sum = sum + times[i]
        numbs[i] = times[i]
    end

    if sum ~= 8 then sleep(0.1) nnumbersto8(amount) return end --if they are not 8, repeat process with cooldown to avoid stack overflow

    --return numbs -- This doesn't work for some reason, nothing gets returned outside the function

    timeunits = numbs
end

nnumbersto8(5) -- manual run it for now
print(unpack(timeunits))
函数睡眠(a)——我找到的随机睡眠函数
本地秒=t编号(操作系统时钟()+a);
而(os.clock()<秒)执行
结束
结束
函数洗牌(tbl)——我找到的随机洗牌函数
对于i=#tbl,2,-1 do
math.randomseed(os.time())
数学随机();数学随机();数学随机();数学随机();
局部j=数学随机(i)
tbl[i],tbl[j]=tbl[j],tbl[i]
结束
返回tbl
结束
当地时间={
0.5,
1.0,
1.5,
2.0,
2.5,
3.0,
3.5,
4
}
本地时间单位={}——参考第49行,我不想这样做。。。
函数nnumbersto8(数量)
局部和=0
局部numbs={}
时间=洗牌(时间)--重新洗牌集合
对于i=1,amount,1do——将前x个值相加
总和=总和+次数[i]
麻木[i]=次数[i]
结束
如果sum~=8,则sleep(0.1)nnumbersto8(amount)返回结束——如果它们不是8,则通过冷却重复该过程以避免堆栈溢出
--return numbs——由于某种原因,这不起作用,函数外不会返回任何内容
时间单位=麻木
结束
nnumbersto8(5)--现在手动运行它
打印(解包(时间单位))
一定有更简单的方法吧?
提前感谢,感谢您的帮助

对于1、2和大于5的值没有解决方案,因此函数只接受3、4和5

在这里,我们对
times
表进行一个浅拷贝,然后从拷贝中获取一个随机索引,并开始搜索解决方案,同时删除使用的值

当地时间={
0.5,
1.0,
1.5,
2.0,
2.5,
3.0,
3.5,
4
}
函数nNumbersTo8(数量)
如果金额<3或金额>5,则
返回{}
结束
局部和=0
局部数={}
本地集={table.unpack(times)}
对于i=1,数量-1,1 do
局部索引=数学随机(#集)
本地值=设置[索引]
如果不是(8<(总和+值)),则
总和=总和+值
表.插入(数字、值)
表.删除(集合,索引)
其他的
打破
结束
结束
本地提醒=8-总和
对于v,ipairs(set)do中的v
如果v==提醒,则
总和=总和+v
表.插入(数字,v)
打破
结束
结束
如果#数字==金额,则
返回号码
其他的
报税表编号第8号(金额)
结束
结束
i=1100 do的

打印(表.拆包(编号8(5)))
结束
答复示例:

1.5 0.5 3   2   1
3   0.5 1.5 1   2
2   3   1.5 0.5 1
3   2   1.5 1   0.5
0.5 1   2   3   1.5

对于1、2和大于5的值没有解决方案,因此函数只接受3、4和5

在这里,我们对
times
表进行一个浅拷贝,然后从拷贝中获取一个随机索引,并开始搜索解决方案,同时删除使用的值

当地时间={
0.5,
1.0,
1.5,
2.0,
2.5,
3.0,
3.5,
4
}
函数nNumbersTo8(数量)
如果金额<3或金额>5,则
返回{}
结束
局部和=0
局部数={}
本地集={table.unpack(times)}
对于i=1,数量-1,1 do
局部索引=数学随机(#集)
本地值=设置[索引]
如果不是(8<(总和+值)),则
总和=总和+值
表.插入(数字、值)
表.删除(集合,索引)
其他的
打破
结束
结束
本地提醒=8-总和
对于v,ipairs(set)do中的v
如果v==提醒,则
总和=总和+v
表.插入(数字,v)
打破
结束
结束
如果#数字==金额,则
返回号码
其他的
报税表编号第8号(金额)
结束
结束
i=1100 do的

打印(表.拆包(编号8(5)))
结束
答复示例:

1.5 0.5 3   2   1
3   0.5 1.5 1   2
2   3   1.5 0.5 1
3   2   1.5 1   0.5
0.5 1   2   3   1.5
这是允许您选择的元素数量的额外限制

解决方案是使用类似于常规子集和的动态规划,但是添加一个额外的变量来指示您使用了多少项

这应该包括以下几行:

Failing stop clauses:
DP[-1][x][n] = false, for all x,n>0  // out of elements
DP[i][-1][n] = false, for all i,n>0  // exceeded X items
DP[i][x][n] = false n < 0            // Passed the sum limit. This is an optimization only if all elements are non negative.
Successful stop clause:
DP[i][0][0] = true for all i >= 0

Recursive formula:
DP[i][x][n] = DP[i-1][x][n] OR DP[i-1][x-1][n-item[i]]  // Watch for n<item[i] case here.
              ^                       ^
      Did not take the item        Used the item
失败停止子句:
DP[-1][x][n]=false,对于所有x,n>0//out-of-element
DP[i][1][n]=false,对于所有i,n>0//超过X项
DP[i][x][n]=false n<0//超过总和限制。只有当所有元素都为非负时,这才是优化。
成功停止条款:
DP[i][0][0]=对于所有i>=0
递归公式:
DP[i][x][n]=DP[i-1][x][n]或DP[i-1][x-1][n-item[i][n//注意n这是一个对允许选择的元素数量有额外限制的选项

解决方案是使用类似于常规子集和的动态规划,但是添加一个额外的变量来指示您使用了多少项

这应该包括以下几行:

Failing stop clauses:
DP[-1][x][n] = false, for all x,n>0  // out of elements
DP[i][-1][n] = false, for all i,n>0  // exceeded X items
DP[i][x][n] = false n < 0            // Passed the sum limit. This is an optimization only if all elements are non negative.
Successful stop clause:
DP[i][0][0] = true for all i >= 0

Recursive formula:
DP[i][x][n] = DP[i-1][x][n] OR DP[i-1][x-1][n-item[i]]  // Watch for n<item[i] case here.
              ^                       ^
      Did not take the item        Used the item
失败停止子句:
DP[-1][x][n]=false,对于所有x,n>0//out-of-element
DP[i][1][n]=false,对于所有i,n>0//超过X项
DP[i][x][n]=false n<0//超过总和限制。只有当所有元素都为非负时,这才是优化。
成功停止条款:
DP[i][0][0]=对于所有i>=0
递归公式:
DP[i][x][n]=DP[i-1][x][n]或DP[i-1][x-1