独特的排列,没有镜像或循环重复

Jor*_*rdi 7 algorithm permutation combinatorics necklaces

一些背景:我正在编写或多或少的强力搜索算法来解决我遇到的问题.为了做到这一点,我需要生成并评估所有可能性,以找出哪个是最好的.由于评估实际上需要一些时间,我宁愿尽可能少地生成完全覆盖我的搜索空间的解决方案.此外,我可以做的更多元素越多越好.对于任何数字K,通常有K!对于高于~10的数字,排列和生成它们都很难.

真正的问题:搜索空间应包含两个元素的所有排列(N次el1和M乘以el2,其中K = M + N),具有以下限制:

  1. 他们必须是独一无二的(即我只想要[aabbb]一次)
  2. 我不需要任何排列的反转(即如果我有[aab],我也不需要[baa])
  3. 我认为排列是圆形的,所以[aab] = [aba] = [baa]

如果我能够做到这一点,可能性的数量将大大减少.由于理想情况下K很大,因此首先生成所有排列然后根据这些标准过滤它们是不可行的.我已经完成了第一个限制(见下文),它将Matlab的正常排列函数(perms)的数量从2 ^ K减少到K!/ N!M !,这是一个巨大的胜利.第二个限制只会将可能性的数量减少一半(在最好的情况下),但我认为第三个也应该能够真正减少可能性的数量.

如果有人知道怎么做,最好还有如何计算会有多少种可能性,这对我有很大的帮助!我更喜欢解释,但代码也很好(我可以读C语言,Java(脚本),Python,Ruby,Lisp/Scheme).


对于感兴趣的:这是迄今为止我只获得唯一排列的算法:

function genPossibilities(n, m, e1, e2)
     if n == 0
         return array of m e2's
     else
         possibilities = genPossibilities(n-1, m, e1, e2)
         for every possibility:
             gain = number of new possibilities we'll get for this smaller possibility*
             for i in max(0,(m+n-gain))
                 if possibility(i) is not e1
                     add possiblity with e1 inserted in position i
         return new possibilities
Run Code Online (Sandbox Code Playgroud)
  • 如果您有N-1和M的所有排列,那么您可以使用它们通过将e1插入其中来查找N和M的排列.你不能只是在任何地方插入,因为那样你就会得到重复.我不知道为什么会这样,但你可以计算出你从旧的可能性中产生的新可能性的数量(我称之为"增益").对于第一个旧排列,该数字从M + 1开始,并且对于每个旧排列减少一个,直到它变为零,此时它返回到M等等(仅当M> = N时才起作用).因此,如果你想计算N = 3和M = 3的排列,并且你有N = 2和M = 3的10个排列,它们的增益将是[4 3 2 1 3 2 1 2 1 1].从排列的长度中减去这个增益,你得到的索引可以在不重复的情况下开始插入新元素.

caf*_*caf 3

您所追求的是 2 元手链的子集(该子集由字符 A 的 n 和字符 B 的 m 定义)。所有手链的集合允许 A 和 B 的数量变化。

以下代码打印出您要查找的序列,并按词汇顺序和恒定的摊销时间执行此操作。它基于Sawada 论文中的通用算法- 有关其工作原理的说明,请参阅该论文。

#include <stdlib.h>
#include <stdio.h>

static int *a;
static int n;

void print_bracelet(int n, int a[])
{
    int i;

    printf("[");
    for (i = 0; i < n; i++)
        printf(" %c", 'a' + a[i]);
    printf(" ]\n");
}

int check_rev(int t, int i)
{
    int j;

    for (j = i+1; j <= (t + 1)/2; j++)
    {
        if (a[j] < a[t-j+1])
            return 0;
        if (a[j] > a[t-j+1])
            return -1;
    }

    return 1;
}

void gen_bracelets(int n_a, int n_b, int t, int p, int r, int u, int v, int rs)
{
    if (2 * (t - 1) > (n + r))
    {
        if (a[t-1] > a[n-t+2+r])
            rs = 0;
        else if (a[t-1] < a[n-t+2+r])
            rs = 1;
    }
    if (t > n)
    {
        if (!rs && (n % p) == 0)
            print_bracelet(n, a + 1);
    }
    else
    {
        int n_a2 = n_a;
        int n_b2 = n_b;

        a[t] = a[t-p];

        if (a[t] == 0)
            n_a2--;
        else
            n_b2--;

        if (a[t] == a[1])
            v++;
        else
            v = 0;

        if ((u == (t - 1)) && (a[t-1] == a[1]))
            u++;

        if ((n_a2 >= 0) && (n_b2 >= 0) && !((t == n) && (u != n) && (a[n] == a[1])))
        {
            if (u == v) {
                int rev = check_rev(t, u);

                if (rev == 0)
                    gen_bracelets(n_a2, n_b2, t + 1, p, r, u, v, rs);

                if (rev == 1)
                    gen_bracelets(n_a2, n_b2, t + 1, p, t, u, v, 0);
            }
            else
                gen_bracelets(n_a2, n_b2, t + 1, p, r, u, v, rs);
        }

        if (u == t)
            u--;

        if (a[t-p] == 0 && n_b > 0)
        {
            a[t] = 1;

            if (t == 1)
                gen_bracelets(n_a, n_b - 1, t + 1, t, 1, 1, 1, rs);
            else
                gen_bracelets(n_a, n_b - 1, t + 1, t, r, u, 0, rs);
        }
    }
}

int main(int argc, char *argv[])
{
    int n_a, n_b;

    if (argc < 3)
    {
        fprintf(stderr, "Usage: %s <a> <b>\n", argv[0]);
        return -2;
    }

    n_a = atoi(argv[1]);
    n_b = atoi(argv[2]);

    if (n_a < 0 || n_b < 0)
    {
        fprintf(stderr, "a and b must be nonnegative\n");
        return -3;
    }

    n = n_a + n_b;
    a = malloc((n + 1) * sizeof(int));

    if (!a)
    {
        fprintf(stderr, "could not allocate array\n");
        return -1;
    }

    a[0] = 0;

    gen_bracelets(n_a, n_b, 1, 1, 0, 0, 0, 0);

    free(a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)