假设{1,2,3,...,m}是一组。我从这个集合中选择了n个不同的元素。我是否可以编写一个算法来计算这些子集的数量,这些子集的总和可以被k整除(排序无关紧要)?
如果订购很重要,这个问题会容易得多,但事实并非如此,我也不知道如何处理。有人可以帮忙吗?
答案 0 :(得分:2)
这可以通过类似于下面概述的方法在时间O(n·k·m)和空间O(n·k)中完成。设S是m元素的集合。根据 set 和 subset 的定义,S的所有元素都是不同的,任何S子集的所有元素都是不同的。
首先,考虑一个更简单的问题,即我们使用任意数量的元素而不是n个元素来计算S子集。令N(W,r)为W子集U的数量,使得ΣU(U的元素之和)等于r mod k。如果W是S的子集,则让W'为W + z,其中z∈S\ W;也就是说,z是S中不存在的元素。现在N(W',(r + z)%k)= N(W,(r + z)%k)+ N(W,r)因为N (W,(r + z)%k)是具有ΣU≡(r + z)%k的W'子集U的数量,其不包含z并且N(W,r)是W'的数量-subsets U与ΣU≡(r + z)%k)确实包含z。重复这种结构,依次处理S的每个元素,直到W'= S,此时所需的答案是N(S,0)。时间是O(k·m),空间是O(k)。
为了使上述过程适应精确的子集大小,将N(W,r)更改为N(W,h,r),其中h是子集大小,并将N(W',r)的等式调整为N(W',h,r)以明显的方式。时间是O(k·n·m),空间是O(k·n)。
答案 1 :(得分:0)
set - >所有元素都不同。
创建一个数组来描述每个数字类有多少代表:</ p>
ncnt=new int[k]
for x in elements{
ncnt[x%k]++;
}
动态编程:
int waysToCreate(int input_class,int class_idx, int n){
int ways=0
// not using this class:
if(class_idx+1 < k )
ways+=waysToCreate(input_class,class_idx+1,n);
for( int i=1;i < ncnt[class_idx] && i<=n ){
int new_input_class=(input_class+i*class_idx)%k;
if(i == n && new_input_class != 0){
break; // all elements are used, but doesn't congrunent with 0 (mod k)
}
int subways=1;
if(class_idx+1 < k )
subways=waysToCreate(new_input_class,class_idx+1,n-i)
ways+=nchoosek(ncnt[class_idx],i) * subways;
}
return ways;
}
在waysToCreate
,nchoosek
答案 2 :(得分:0)
它可以工作但很慢
/**
* List all k size subset of a given list with n unique elements.
* n can be bigger than 64. this function will take O(K^N) time, Bad.
*
* @param list
* @param subSetSize
* @param subSet
* @param indexFrom
* @param indexEnd
*/
private static void subSetOf(List<Integer> list, int subSetSize, Set<Integer> subSet, int indexFrom, int indexEnd) {
if (subSet == null) {
assert 0 < subSetSize && subSetSize <= list.size();
subSet = new HashSet(subSetSize);
}
if (subSetSize <= 64) {
// Todo using bitwise trick
}
for (int index = indexFrom; index <= indexEnd; index++) {
subSet.add(list.get(index));
if (subSet.size() == subSetSize) {
System.out.println(Arrays.toString(subSet.toArray()));
// check the sum of this subset is satisfied or not by sum/k
}
if (subSet.size() < subSetSize) {
subSetOf(list, subSetSize, subSet,
index + 1,
list.size() - (subSetSize - subSet.size()));
}
subSet.remove(list.get(index));
}
}
public static void subSetOf(List<Integer> list,
int subSetSize,
Set<Integer> subSet) {
subSetOf(list, subSetSize, subSet, 0, list.size() - subSetSize);
}