Java 如何改进生成多集组合的算法?

Java 如何改进生成多集组合的算法?,java,c++,algorithm,optimization,Java,C++,Algorithm,Optimization,如何在生成有界多集组合的以下生成器中优化next()和hasNext()方法?(C++和java java),因为这是C++兼容的,没有Java特定元素,它不直接转换成C++。 算法中存在问题的特定区域是整个hasNext()方法,该方法可能不必要地复杂,以及行: if(当前[xSlot]>0)aiItemsUsed[current[xSlot]]; 我有一个早期版本的算法,在return语句之前有一些回溯,因此有一个更简单的hasNext()测试,但我无法让这个版本工作 这个算法的背景是很难找

如何在生成有界多集组合的以下生成器中优化
next()
hasNext()
方法?(C++和java java),因为这是C++兼容的,没有Java特定元素,它不直接转换成C++。 算法中存在问题的特定区域是整个
hasNext()
方法,该方法可能不必要地复杂,以及行:

if(当前[xSlot]>0)aiItemsUsed[current[xSlot]];

我有一个早期版本的算法,在return语句之前有一些回溯,因此有一个更简单的
hasNext()
测试,但我无法让这个版本工作

这个算法的背景是很难找到。例如,在Knuth 7.2.1.3中,他只是说它可以完成(并给出了一个练习来证明算法是可能的),但没有给出算法。同样,我有六篇关于组合学的高级文本(包括Papadimitriou和Kreher/Stimson)他们中没有一个给出生成多集组合的算法。Kreher将其作为“读者练习”。无论如何,如果你能像上面那样改进算法或提供比我更有效的工作实现参考,我将不胜感激。请只给出迭代算法(请不要递归)

/**迭代器返回一个基于1的整数数组。当达到最后一个组合时,hasNext()将为false。
*@param aiItems一个基于数组,包含每个唯一项目类型的可用项目数,其中aiItems[0]是项目类型数
*@param ctSlots项目进入的插槽数
*@返回迭代器,该迭代器生成包含组合的基于1的数组,或在发生错误时返回null。
*/
公共静态java.util.Iterator组合(final int[]aiItems,final int ctSlots){//multiset组合到有限数量的插槽中
组合迭代器迭代器=新组合迭代器(){
int-xSlot;
int-xItemType;
int-ctItemType;
int[]当前=新int[ctSlots+1];
int[]aiItemsUsed=新int[aiItems[0]+1];
{reset();当前[0]=ctSlots;ctItemType=aiItems[0];}
公共布尔hasNext(){
int xUseSlot=ctSlots;
int iCurrentType=ctItemType;
int-ctItemsUsed=0;
int ctTotalItemsUsed=0;
while(true){
int xUsedType=当前[xUseSlot];
if(xUsedType!=iccurrentType)返回true;
ctItemsUsed++;
ctTotalItemsUsed++;
if(ctTotalItemsUsed==ctSlots)返回false;
if(ctItemsUsed==aiItems[xUsedType]){
i当前类型--;
ctItemsUsed=0;
}
许塞斯洛特;
}
}
公共int[]下一个(){
while(true){
while(xItemType==ctItemType){
xSlot--;
xItemType=current[xSlot];
}
xItemType++;
while(true){
而(aiItemsUsed[xItemType]==aiItems[xItemType]&&xItemType!=当前[xSlot]){
while(xItemType==ctItemType){
xSlot--;
xItemType=current[xSlot];
}
xItemType++;
}
如果(当前[xSlot]>0)aiItemsUsed[current[xSlot]]--;
当前[xSlot]=xItemType;
aiItemsUsed[xItemType]++;
if(xSlot==ctSlots){
回流;
}
xSlot++;
}
}
}
public int[]get(){返回当前;}
public void remove(){}
公共无效集(int[]current){this.current=current;}
公共void设置值(int[]当前值){
如果(this.current==null | | this.current.length!=current.length)this.current=new int[current.length];
System.arraycopy(当前,0,this.current,0,current.length);
}
公共无效重置(){
xSlot=1;
xItemType=0;
Arrays.fill(当前,0);当前[0]=ctSlots;
fill(aiItemsUsed,0);aiItemsUsed[0]=aiItems[0];
}
};
返回迭代器;
}
附加信息

到目前为止,一些受访者似乎不理解集合和有界多集合之间的区别。有界多集合有重复的元素。例如,{a,a,b,b,c}是有界多集合,在我的算法中编码为{3,2,3,1}。请注意,前导的“3”是项目类型(唯一项目)的数量如果您提供了一个算法,那么下面的测试应该产生如下所示的输出

    private static void combination_multiset_test(){
        int[] aiItems = { 4, 3, 2, 1, 1 };
        int iSlots = 4;
        java.util.Iterator<int[]> iterator = combination( aiItems, iSlots );
        if( iterator == null ){
            System.out.println( "null" );
            System.exit( -1 );
        }
        int xCombination = 0;
        while( iterator.hasNext() ){
            xCombination++;
            int[] combination = iterator.next();
            if( combination == null ){
                System.out.println( "improper termination, no result" );
                System.exit( -1 );
            }
            System.out.println( xCombination + ": " + Arrays.toString( combination ) );
        }
        System.out.println( "complete" );
    }


1: [4, 1, 1, 1, 2]
2: [4, 1, 1, 1, 3]
3: [4, 1, 1, 1, 4]
4: [4, 1, 1, 2, 2]
5: [4, 1, 1, 2, 3]
6: [4, 1, 1, 2, 4]
7: [4, 1, 1, 3, 4]
8: [4, 1, 2, 2, 3]
9: [4, 1, 2, 2, 4]
10: [4, 1, 2, 3, 4]
11: [4, 2, 2, 3, 4]
complete
private static void composition\u multiset\u test(){
int[]aiItems={4,3,2,1,1};
int iSlots=4;
java.util.Iterator迭代器=组合(aiItems,iSlots);
if(迭代器==null){
System.out.println(“空”);
系统退出(-1);
}
int xCombination=0;
while(iterator.hasNext()){
xCombination++;
int[]组合=迭代器.next();
if(组合==null){
System.out.println(“不当终止,无结果”);
系统退出(-1);
}
System.out.println(xCombination+“:”+Arrays.toString(组合));
}
系统输出打印项次(“完成”);
}
1: [4, 1, 1, 1, 2]
2: [4
    private static void combination_multiset_test(){
        int[] aiItems = { 4, 3, 2, 1, 1 };
        int iSlots = 4;
        java.util.Iterator<int[]> iterator = combination( aiItems, iSlots );
        if( iterator == null ){
            System.out.println( "null" );
            System.exit( -1 );
        }
        int xCombination = 0;
        while( iterator.hasNext() ){
            xCombination++;
            int[] combination = iterator.next();
            if( combination == null ){
                System.out.println( "improper termination, no result" );
                System.exit( -1 );
            }
            System.out.println( xCombination + ": " + Arrays.toString( combination ) );
        }
        System.out.println( "complete" );
    }


1: [4, 1, 1, 1, 2]
2: [4, 1, 1, 1, 3]
3: [4, 1, 1, 1, 4]
4: [4, 1, 1, 2, 2]
5: [4, 1, 1, 2, 3]
6: [4, 1, 1, 2, 4]
7: [4, 1, 1, 3, 4]
8: [4, 1, 2, 2, 3]
9: [4, 1, 2, 2, 4]
10: [4, 1, 2, 3, 4]
11: [4, 2, 2, 3, 4]
complete
template<typename Lambda>
void for_each_bit( my_bignum const& num, Lambda&& func )
#include <utility>
#include <cstddef>
#include <vector>

using std::size_t;

namespace details {
template<typename Lambda>
  void for_each_multiset_combo_worker( std::vector<size_t> const& counts, Lambda&& lambda, std::vector<size_t>& indexes, std::vector<size_t>& current )
  {
    if (depth >= counts.size()) {
      lambda( current );
      return;
    }
    for (size_t i = 0; i <= counts[depth]; ++i) {
      // Assert: current.size() == depth
      current.push_back(i);
      // Assert: current.back() == i
      // Assert: current.size() == dpeth+1
      for_each_multiset_combo_worker( counts, lambda, depth+1, current );
      // Assert: current.back() == i
      // Assert: current.size() == dpeth+1
      current.pop_back();
      // Assert: current.size() == depth
    }
  }
}
template<typename Lambda>
void for_each_multiset_combo( std::vector<size_t> const& counts, Lambda&& lambda )
{
  std::vector<size_t> current;
  current.reserve( counts.size() );
  details::for_each_multiset_combo_worker( counts, std::forward<Lambda>(lambda), 0, current );
}
#include <iostream>

int main() {
  std::vector<size_t> multiset = {3, 2, 1, 1};
  size_t counter = 0;
  for_each_multiset_combo( multiset, [&]( std::vector<size_t> const& counts ){
    std::cout << counter << ": [";
    for(auto it = counts.begin(); it != counts.end(); ++it) {
      if (it != counts.begin()) {
        std::cout << ", ";
      }
      std::cout << *it;
    }
    std::cout << "]\n";
    ++counter;
  });
}
#include <utility>
#include <cstddef>
#include <vector>

using std::size_t;

template<typename Lambda>
void for_each_multiset_combo( std::vector<size_t> const& counts, Lambda&& lambda )
{
  // below code is easier if I assume counts is non-empty:
  if (counts.empty())
  {
    lambda(counts);
    return;
  }
  // preallocate a buffer big enough to hold the output counts:
  std::vector<size_t> indexes;
  indexes.reserve( counts.size() );
  while(true) {
    // append 0s on the end of indexes if we have room:
    while (indexes.size() < counts.size()) {
      indexes.push_back(0);
    }
    // at this point, we have a unique element.  Pass it to the passed in lambda:
    lambda( indexes );
    // The advancement logic.  Advance the highest index.  If that overflows, pop it and
    // advance the next highest index:
    indexes.back()++;
    while (indexes.back() > counts[indexes.size()-1]) {
      indexes.pop_back();
      // we are done if we have managed to advance every index, and there are none left to advance:
      if (indexes.empty())
        return; // finished
      indexes.back()++;
    }
  }
}
#include <iostream>

int main() {
  std::vector<size_t> multiset = {3, 2, 1, 1};
  size_t counter = 0;
  for_each_multiset_combo( multiset, [&]( std::vector<size_t> const& counts ){
    std::cout << counter << ": [";
    for(auto it = counts.begin(); it != counts.end(); ++it) {
      if (it != counts.begin()) {
        std::cout << ", ";
      }
      std::cout << *it;
    }
    std::cout << "]\n";
    ++counter;
  });
}
haves[i] := multiplicity of the i-th item in the collection
target := output collection must have this size
class Perm(object):
    def __init__(self,items,haves,target):
        assert sum(haves) >= target
        assert all(h > 0 for h in haves)
        self.items = items
        self.haves = haves
        self.target = target
        self.ans = None
        self.stop = False
    def __iter__(self):
        return self
    def reset(self):
        self.ans = [0]*len(self.haves)
        self.__fill(self.target)
        self.stop = False
    def __fill(self,n):
        """fill ans from LSB with n bits"""
        if n <= 0: return
        i = 0
        while n > self.haves[i]:
            assert self.ans[i] == 0
            self.ans[i] = self.haves[i]
            n -= self.haves[i]
            i += 1
        assert self.ans[i] == 0
        self.ans[i] = n
    def __inc(self):
        """increment from LSB, carry when 'target' or 'haves' constrain is broken"""
        # in fact, the 'target' constrain is always broken on the left most non-zero entry
        # find left most non-zero
        i = 0
        while self.ans[i] == 0:
            i += 1
        # set it to zero
        l = self.ans[i]
        self.ans[i] = 0
        # do increment answer, and carry
        while True:
            # increment to the next entry, if possible
            i += 1
            if i >= len(self.ans):
                self.stop = True
                raise StopIteration
            #
            if self.ans[i] == self.haves[i]:
                l += self.ans[i]
                self.ans[i] = 0
            else:
                l -= 1
                self.ans[i] += 1
                break
        return l
    def next(self):
        if self.stop:
            raise StopIteration
        elif self.ans is None:
            self.reset()
        else:
            l = self.__inc()
            self.__fill(l)
        return self.ans
test_cases = [([3,2,1], 3),
              ([3,2,1], 5),
              ([3,2,1], 6),
              ([4,3,2,1,1], 4),
              ([1,3,1,2,4], 4),
             ]

P = Perm(None,*test_cases[-1])
for p in P:
    print p
    #raw_input()
[1, 3, 0, 0, 0]
[1, 2, 1, 0, 0]
[0, 3, 1, 0, 0]
[1, 2, 0, 1, 0]
[0, 3, 0, 1, 0]
[1, 1, 1, 1, 0]
[0, 2, 1, 1, 0]
[1, 1, 0, 2, 0]
[0, 2, 0, 2, 0]
[1, 0, 1, 2, 0]
[0, 1, 1, 2, 0]
[1, 2, 0, 0, 1]
[0, 3, 0, 0, 1]
[1, 1, 1, 0, 1]
[0, 2, 1, 0, 1]
[1, 1, 0, 1, 1]
[0, 2, 0, 1, 1]
[1, 0, 1, 1, 1]
[0, 1, 1, 1, 1]
[1, 0, 0, 2, 1]
[0, 1, 0, 2, 1]
[0, 0, 1, 2, 1]
[1, 1, 0, 0, 2]
[0, 2, 0, 0, 2]
[1, 0, 1, 0, 2]
[0, 1, 1, 0, 2]
[1, 0, 0, 1, 2]
[0, 1, 0, 1, 2]
[0, 0, 1, 1, 2]
[0, 0, 0, 2, 2]
[1, 0, 0, 0, 3]
[0, 1, 0, 0, 3]
[0, 0, 1, 0, 3]
[0, 0, 0, 1, 3]
[0, 0, 0, 0, 4]