代码之家  ›  专栏  ›  技术社区  ›  Thomas Ahle

在盒子中生成球

  •  2
  • Thomas Ahle  · 技术社区  · 16 年前

    给定两个排序向量 a b ,查找所有向量的和 还有一些排列 ,并且一旦排序,它是唯一的。

    您可以按以下方式创建一个搜索向量:

    • 取向量 向量的排列 .
    • 把它们加起来 c[i]=a[i]+b[i] .
    • 排序 c .

    我有兴趣找到 -产生整组唯一的 C 向量。

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

    我想这和 M 球在 盒子(每个盒子一个),有些球和盒子是相同的。
    更新: 给定字符串 a='aabbbcdddd' b='xxyyzzttqq' 你的问题是4个盒子里有10个球。有4个不同的盒子,大小分别为2、3、1和4。球是成对的,不可区分。

    例1: 给定的字符串是 a='xyy' b='kkd' .
    可能的解决方案: 'kkd' , 'dkk' .
    原因: 我们看到所有独特的排列 “KKD” , 'kdk' “DKK” . 然而,在我们的约束下,前两个排列被认为是相等的,因为不同的排列映射到相同的字符上。 “Y” .

    例2: 给定的字符串是 A =‘XYY’ b='khd' .
    可能的解决方案: 'khd' , 'dkh' , 'hkd' .

    例3: 给定的字符串是 a='xxxx' b='khhd' .
    可能的解决方案: 'khhd' .

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

    作为我的 通常非常大,而且由于字符串中的相似性很常见,所以我现在生成的方法更多 比实际通过集合过滤器的排列。我希望有一个直接生成正确的算法。欢迎有任何改进。

    2 回复  |  直到 16 年前
        1
  •  2
  •   Community Mohan Dere    9 年前

    要生成可能重复元素(多集)的k-组合,以下可能有用: A Gray Code for Combinations of a Multiset (1995) .

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

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

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

    0和l=;

    和Yi=K。

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

    其想法是,固定char 1出现的次数(y1)。然后递归地从其余部分生成k-y1的所有组合。

    psuedocode:

    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,看看恰好出现一次的符号。假设有k个这样的符号。然后,您需要生成所有可能的b排列,其中包含k元素,并在相应的位置映射到这些符号。其余的可以忽略/根据需要填写。

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

    我假设XXYY只给出1个唯一的字符串,并且恰好出现一次的字符串是“区别”点。

    以防万一 a=xyy, b=add

    区别点是X

    所以选择长度为1的“添加”的排列。那些给你 a d .

    因此 add dad (or dda) 是你需要的。

    为了 a=xyyz b=good

    区别点是X和Z

    所以你产生长度为2的b排列

    go
    og
    oo
    od
    do
    gd
    dg
    

    给你7个独特的排列。

    有帮助吗?我的理解正确吗?

        2
  •  0
  •   Thomas Ahle    16 年前

    好吧,很抱歉,我一直无法清楚地解释这个问题,但这里有一个解决方案。

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

    为了解决这个问题,我们将使用递归生成器。我们浏览了所有适合框1的组合和对其余框的追索权,禁止我们已经选择的值。为了完成禁令, 组合 将在多个调用之间维护一个位数组。

    在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'