我是算法的新手,在网上发现了这个问题: 给定N个数字序列S1,...,SN(-20,000,000≤Si≤20,000,000),确定S(包括空子集)的子集有多少A和B之和(-500,000,000≤A≤B≤500,000,000) ),包容性。
For EXAMPLE:
Sequence : 1 -2 3
A= -2
B=3
The following 5 subsets have a sum between -1 and 2:
0 = 0 (the empty subset)
1 = 1
1 + (-2) = -1
-2 + 3 = 1
1 + (-2) + 3 = 2
我的方法:
采取所有可能的组合,即j=2^n
并检查总和
代码:
for(int i=0;i<j;i++){
for(int k=0;k<A.length;k++){
int temp= 1<<k;
if( (i&temp) !=0){
sum+=A[k];
}
}
if(a<=sum && sum<=b){
ans++;
sum=0;
}
cout<<ans<<endl;
}
CONS:
如果n> 27的价值,这个解决方案在我退休之前不会给我答案,我想去电影星际,它会变得很棒。任何人都可以建议我一个好的算法或者解决这个问题的方法
据我说,我应该对阵列进行排序并根据A和B分割阵列
答案 0 :(得分:0)
好的,扩展我的评论......
您可以通过以下方式解决此问题: -
for a set S and range AB
for each element in S
remove element from S, call new set S'
calculate new range A'B', where A' and B' are altered according to the removed element
call this function using S' and A'B'
如果S的大小只有一个,那么: -
is element of S within range AB?
我不知道这是否是最有效的解决方案,但如果没有进一步的研究,这将是我最初的解决方案。可能会有一个更快的方式,但这对我来说非常NP。
递归是在行中调用此函数&#39;和一个谷歌的递归&#39;将提供有关该技术的更多细节。
答案 1 :(得分:0)
我们首先找到包含1个元素的解决方案,然后找到包含2,3个元素的解决方案......称之为M
首先对集合进行排序。
对于任何M,我们可以按重力顺序向左递归生成组合,例如:
XX ...
x.x中..
.XX ..
X..X。
.X.X。
.. XX
等
让我假设对于这个序列中的任何成员,我们知道如何制作下一个或前一个,以及任何M。
现在我认为这个列表是总价值的顺序,所以你知道什么时候在A和B处切断它。对于M = 1,你只需要巡航到A,开始输出解决方案,然后停止超出B,但您还要注意超过AS [0]的索引,S [0]是集合中的最小数字。
现在你开始你的M = 2运行,其中包含一个刚刚超过A-S [0]并且抛出S [0]的解决方案。这是M = 2的最小解。所以一直巡航直到你超过B.
现在M = 3的起点并不那么简单。候选者具有较低的tot + x值,其中x是提供的数字但不在该集合中。您可以按顺序搜索M = 2设置,并在tot-A超过已找到的解决方案的x时停止。
适用于M的所有后续值。
但是我不确定这个序列是否真的按价值顺序排列,而且我不确定如何编写给出序列中下一个组合的算法。还是我?怎么样:
对于任何组合,要按顺序制作下一个组合,请找到所有下行边缘,例如在XX.X.我们在第二和第四个X之后有下行边缘。对于每条边,计算交换X和的结果。它的任何一方。选择产生最小差异的选项。如果它们产生相同的差异,则选择最左边的边缘。现在很明显如何在序列中制作前一个。