在盒子里生成球

时间:2010-06-18 23:16:28

标签: algorithm permutation combinatorics

给定两个已排序的向量ab,找到ab的某些排列之和的所有向量,并且这些向量一旦排序就是唯一的。

您可以通过以下方式创建一个搜索到的向量:

  • 采用向量a和向量b的排列。
  • 将它们汇总起来c[i]=a[i]+b[i]
  • 排序c

我有兴趣找到一组b - 排列,这些排列会产生一整套独特的c向量。

示例0 a='ccdd'b='xxyy'
给出求和向量:'cycydxdx''cxcxdydy''cxcydxdy' 请注意b'xyxy''yxyx'的排列相等,因为在这两种情况下,“box c”和“box d”都只得到一个'x'和一个'y'

我想这类似于将M球放入M方框中(每个方框一个),其中一组球和方框相同。
更新:鉴于字符串a='aabbbcdddd'b='xxyyzzttqq',您的问题将是4个方框中的10个球。有4个不同的盒子,大小分别为2,3,1和4.这些球是完全无法区分的。

示例1:鉴于字符串为a='xyy'b='kkd' 可能的解决方案:'kkd''dkk'
原因:我们发现b的所有唯一排列都是'kkd''kdk''dkk'。但是,根据我们的约束,两个第一个排列被认为是相等的,因为不同的索引映射到字符串'y'中的相同字符a

示例2:鉴于字符串为a='xyy'b='khd' 可能的解决方案:'khd''dkh''hkd'

示例3:鉴于字符串为a='xxxx'b='khhd' 可能的解决方案:'khhd'

我可以使用在Wikipedia/Permutation上描述的Narayana Pandita算法来解决生成唯一候选b排列的问题。
第二部分接缝更难。我最好的方法是将两个字符串成对连接到一个列表,对其进行排序并将其用作查找集中的键。 ('xx' + 'hd'加入→'xh','xd'排序→'xd','xh')。

由于我的M通常非常大,并且由于字符串中的相似性很常见,因此我目前生成的b排列方式比实际通过设置过滤器更多{{1}}排列。我希望有一个算法直接生成正确的算法。欢迎任何改进。

2 个答案:

答案 0 :(得分:2)

要生成可能重复元素的k组合(multiset),以下内容可能很有用:A Gray Code for Combinations of a Multiset (1995)

对于递归解决方案,请尝试以下操作:

计算每个角色出现的次数。假设它们是x1 x2 ... xm,对应于m个不同的字符。

然后你需要找到所有可能的有序对(y1 y2 ... ym),这样

0< = yi< = xi

和Sum yi = k。

这里yi是我出现的字符的次数。

想法是,修复char 1出现的次数(y1)。然后递归地生成剩余的k-y1的所有组合。

伪码:

List Generate (int [] x /* array index starting at 1*/, 
               int k /* size of set */) {

    list = List.Empty;

    if (Sum(x) < k) return list;

    for (int i = 0; i <= x[1], i++) {

        // Remove first element and generate subsets of size k-i.

        remaining = x.Remove(1);

        list_i = Generate(remaining, k-i);

        if (list_i.NotEmpty()) {

            list = list + list_i;    

        } else {

            return list;
        }

    }

    return list;
}

编辑前:

如果我理解正确,你需要查看字符串a,查看恰好出现一次的符号。说有这样的符号。然后,您需要生成b的所有可能排列,其中包含k个元素并映射到相应位置的那些符号。其余的你可以忽略/填写你认为合适的。

我记得在这里发布了C#代码:How to find permutation of k in a given length?

我假设xxyy只会给出一个唯一的字符串,那些只出现一次的字符串就是“区别”。

例如a=xyy, b=add

区别点是x

因此,您选择长度为1的“添加”。这些会为您提供ad

因此,您需要adddad (or dda)

a=xyyz b=good

区别点是x和z

因此,您生成长度为2的b的排列

go
og
oo
od
do
gd
dg

为您提供7种独特的排列。

这有帮助吗?我的理解是否正确?

答案 1 :(得分:0)

好的,对不起,我从来没能清楚地解释这个问题,但这是一个解决方案。

我们需要两个函数combinationsrunvector(v)combinations(s,k)生成长度为k的多集的唯一组合。对于s='xxyy',这些将是['xx','xy','yy']runvector(v)将表示为排序向量的多集转换为更简单的结构,即运行向量。 runvector('cddeee')=[1,2,3]

要解决这个问题,我们将使用递归生成器。我们贯穿了适用于box1的所有组合以及对其余框的追索,禁止我们已经选择的值。要完成禁止,combinations将在所有通话中保持一种比特。

在python中,方法如下:

def fillrest(banned,out,rv,b,i):
    if i == len(rv):
        yield None
        return
    for comb in combinations(b,rv[i],banned):
        out[i] = comb
        for rest in fillrest(banned,out,rv,b,i+1):
            yield None

def balls(a,b):
    rv = runvector(a)
    banned = [False for _ in b]
    out = [None for _ in rv]
    for _ in fill(out,rv,0,b,banned):
        yield out[:]

>>> print list(balls('abbccc','xyyzzz'))
[['x', 'yy', 'zzz'],
 ['x', 'yz', 'yzz'],
 ['x', 'zz', 'yyz'],
 ['y', 'xy', 'zzz'],
 ['y', 'xz', 'yzz'],
 ['y', 'yz', 'xzz'],
 ['y', 'zz', 'xyz'],
 ['z', 'xy', 'yzz'],
 ['z', 'xz', 'yyz'],
 ['z', 'yy', 'xzz'],
 ['z', 'yz', 'xyz'],
 ['z', 'zz', 'xyy']]

输出采用'box'格式,但很容易合并回简单字符串:'xyyzzzz''xyzyzz' ...