将数字表示为数组子集的总和

时间:2015-08-24 23:47:00

标签: algorithm dynamic-programming

给定自然数S> 10,我想生成N个自然数A =(a1,a2,...,aK,...,aN)的数组,使得S是M ai的总和。

约束1:

ai < S/2

约束2:

M >= K

约束3(可选):ai != aj

很抱歉,我不确定如何使用正确的数学符号来描述这个问题,但这个想法很简单:生成一些可以累加到预定义总数的值。然后添加一些更多的值(“诱饵”原样),使选择正确值的任务变得更加困难。

让我们说S = 18,我希望它被表示为至少3个值的总和。所以,一个&#34;赢得&#34;数组将是A =(7,8,3,4,5),因为7 + 8 + 3 = 18并且没有办法使用少于3个值来获得18。

我已经有了一个简单的算法:

Input: 
S - the sum
K - the number of values required to add up to S
N - the total number of values (includes the decoys)

Output: 
A - the array of values ai

1) Generate K values by dividing S by K and then adding and subtracting some random numbers. This ensures that ai will be more or less random while still adding up to S.

2) Generate (N-K) random values less than S/2 each.

3) Combine all the generated values into one array A.

4) Test that S can be represented as a sum of no less than K values from the array A. If not, discard A and return to 1)

Example:
S = 20
K = 3
N = 5
ai values generated: 7, 1, 12, 4, 8,
7+1+12=20 – This is what we need (3 values add up to 20)

But we also can get 20 with only 2 values and this violates Constraint 2:
12+8 = 20

当然,这是一种蛮力方法,我检查过多次迭代,但显然不是正确的方法。

我的问题:是否可以生成数组A,以便它自动满足约束1,2,3或至少约束1,2?

1 个答案:

答案 0 :(得分:0)

对于正整数,简短的答案是否定的:反例 S = 1 K = 2。但是,避免明显的,

createLongList(S,K)
{
  list= {};
  for(i=1 to s/2)
    if(canAdd(list,S,K,i))
      list.add(i);
    else break;
}

这会创建最大尺寸列表吗?也许不是,但它会做得很好。没有进入数学,递归搜索将提供有保证的最佳结果。

#list=={} the first time, istart=S/2
createLongList(S,list,K,istart)
{
  bestList=list;
  for(i=istart to 1)
     if(canAdd(list,S,K,i))
       newList=createLongList(S,list++i,K,i-1);
       if(newList.isLongerThan(bestList))
         bestList=newList;
  return bestList;
}