Algorithm 从n“的堆栈中查找k个元素的所有组合的算法;随机地;

Algorithm 从n“的堆栈中查找k个元素的所有组合的算法;随机地;,algorithm,combinations,Algorithm,Combinations,我有一个类似于这里描述的问题: 我正在寻找类似的东西,包括从n到k的所有可能组合。但是,我需要一个子集来与之前绘制的子集有很大的不同。例如,如果我要从8个元素的集合中绘制3个元素的子集,则以下算法对我没有用处,因为每个子集都与之前绘制的子集非常相似: 11100000, 11010000, 10110000, 01110000, 我正在寻找一种算法,该算法以更“随机”的方式选择子集,即一个子集中的大多数元素在下一个子集中不被重用: 11100000, 00010011, 00101100,

我有一个类似于这里描述的问题:

我正在寻找类似的东西,包括从n到k的所有可能组合。但是,我需要一个子集来与之前绘制的子集有很大的不同。例如,如果我要从8个元素的集合中绘制3个元素的子集,则以下算法对我没有用处,因为每个子集都与之前绘制的子集非常相似:

11100000, 11010000, 10110000, 01110000,

我正在寻找一种算法,该算法以更“随机”的方式选择子集,即一个子集中的大多数元素在下一个子集中不被重用:

11100000, 00010011, 00101100,

有人知道这样的算法吗

我希望我的问题有意义,有人能帮我解决()

亲切问候,


Christian

随机选择k元素怎么样。即选择p在1和n之间随机的pth,然后对剩下的进行重新排序,并选择q在1和n-1之间的qth,以此类推


也许我误解了。你还想要所有的可能性吗?在这种情况下,您总是可以先生成它们,然后从列表中选择随机项

首先从n中生成k的所有可能组合,然后借助随机函数重新排列它们

如果在向量中有结果,则在向量中循环:对于每个元素,让它随元素在随机位置改变位置

当然,对于较大的k和n来说,这会变慢。

通过“随机查找”,我想你指的是词典中的距离。。这是否适用于组合
i
i-1
,或
i
与之前的所有组合

如果是,以下是一些建议:

  • 由于大多数组合器产生有序输出,因此有两种选择:

  • 设计或找到一个以某种方式产生非有序输出的发生器
  • 在一个绑定数组文件/db中枚举并存储足够的/所有组合
  • 如果您决定使用door#2,那么您可以通过1和组合的#之间的随机整数访问随机排序的组合

  • 作为最后一项检查,使用组合之间的差异/距离度量来比较当前和以前的组合,例如,对于Perl中的无符号
    Bit::Vector

    $vec1->Lexicompare($vec2)>=$MIN\u LEX\u DIST

  • 您可以在门#1后面再看一眼,因为即使是
    n
    k
    的中等值,也可以得到一个大数组:

编辑:


刚刚看到你对安克的评论。。。也许lexicompare仍然可以帮助您跳过类似的组合?

这并不是随机的,但根据您的需要,它可能适合您

  • 计算可能的组合数。让我们把它们命名为N
  • 计算一个与N互质的大数,我们把它命名为P
  • 对组合进行排序,给它们取1到N的数字。让我们把它们命名为C1到CN
  • 迭代输出组合。第一个是VP mod N,第二个是C2*P mod N,第三个是C3*P mod N,等等。本质上,Outputi=Ci*P mod N。mod表示模运算符

  • 如果仔细选择p,您将得到看似随机的组合。接近1或N的值将产生差异很小的值。最好选择接近N/4或N/5的值。您还可以为您需要的每个迭代随机生成P。

    作为我的后续评论,下面是一些代码,允许您根据“索引”以colex顺序确定子集的组成。 不知羞耻地从我自己的任务中偷来

    //////////////////////////////////////
    // NChooseK
    //
    // computes    n!
    //          --------
    //          k!(n-k)!
    //
    // using Pascal's identity
    // i.e. (n,k) = (n-1,k-1) + (n-1,k)
    //
    // easily optimizable by memoization
    long long NChooseK(int n, int k)
    {
        if(k >= 0 && k <= n && n >= 1)
        {
            if( k > n / 2)
                k = n - k;
            if(k == 0 || n == 0)
                return 1;
            else
                return NChooseK(n-1, k-1) + NChooseK(n-1, k);
        } 
        else
            return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////
    // SubsetColexUnrank
    //  The unranking works by finding each element
    //  in turn, beginning with the biggest, leftmost one.
    //  We just have to find, for each element, how many subsets there are
    //  before the one beginning with the elements we have already found.
    //
    // It stores its results (indices of the elements present in the subset) into T, in ascending order.
    void SubsetColexUnrank(long long r, int * T, int subsetSize)
    {
        assert( subsetSize >= 1 );
    
        // For each element in the k-subset to be found
        for(int i = subsetSize; i >= 1; i--)
        {
            // T[i] cannot be less than i
            int x = i;
    
            // Find the smallest element such that, of all the k-subsets that contain it,
            // none has a rank that exceeds r.            
            while( NChooseK(x, i) <= r )
                x++;
    
            // update T with the newly found element
            T[i] = x;
    
            // if the subset we have to find is not the first one containing this element
            if(r > 0)
            {
                // finding the next element of our k-subset
                // is like finding the first one of the same subset
                // divided by {T[i]}
                r -= NChooseK(x - 1, i);
            }
        }
    }
    
    //////////////////////////////////////
    //恩乔塞克
    //
    //计算n!
    //          --------
    //k!(n-k)!
    //
    //使用帕斯卡恒等式
    //即(n,k)=(n-1,k-1)+(n-1,k)
    //
    //易于通过记忆进行优化
    长NChooseK(整数n,整数k)
    {
    如果(k>=0&&k=1)
    {
    如果(k>n/2)
    k=n-k;
    如果(k==0 | | n==0)
    返回1;
    其他的
    返回NChooseK(n-1,k-1)+NChooseK(n-1,k);
    } 
    其他的
    返回0;
    }
    ///////////////////////////////////////////////////////////////////////
    //次级综合银行
    //取消分级的工作方式是查找每个元素
    //反过来,从最大最左边的一个开始。
    //我们只需要找到,对于每个元素,有多少子集
    //在我们已经找到的元素开始之前。
    //
    //它将其结果(子集中元素的索引)按升序存储到T中。
    void subsetclexunrank(长-长r,int*T,int subsetSize)
    {
    断言(子集大小>=1);
    //对于要查找的k子集中的每个元素
    对于(int i=subsetSize;i>=1;i--)
    {
    //T[i]不能小于i
    int x=i;
    //找到最小的元素,在包含它的所有k-子集中,
    //没有一个等级超过r。
    while(NChooseK(x,i)0)
    {
    //寻找k-子集的下一个元素
    //就像找到同一子集的第一个一样
    //除以{T[i]}
    r-=NChooseK(x-1,i);
    }
    }
    }
    
    随机输入,随机输出


    colex顺序是这样的,它的unranking函数不需要从中选择要工作的元素的集合的大小;元素的数量假定为NChooseK(集合的大小,子集的大小)。

    根据您要做的事情,您可以做扑克牌之类的事情。保留两个列表:
    Source
    是您的源(未使用)列表;第二个是“已拾取”列表。当您从
    Source
    中随机选取
    k
    项时,您会将它们移动到您的
    Used
    列表中

    如果中有
    k