哪种算法可用于解决这种相似性,最小化均衡概率?

时间:2016-06-23 21:23:50

标签: algorithm sorting grouping partitioning minimization

我到处寻找,但显然我似乎无法找到正确的关键字来搜索合适的解决方案,所以问题出现了:

*

  

我有一组P元素[A,B .... Y,Z]和一个PxP值矩阵   它代表了每对元素之间的相似性(所以   主对角线为100%,每隔一个单元格的数字在0%和0之间   100%)。我想将此集合划分为N个元素的组,以便   该解决方案倾向于最小化组的平均内部相似性

*

你能告诉我如何做到这一点吗?我已经尝试过研究标准分区算法,但大多数都不适用,因为权重取决于对,而不是个体。

谢谢!

2 个答案:

答案 0 :(得分:0)

不幸的是,这个问题是NP难的,这意味着不可能有一个多项式时间算法来解决每个实例的最优性。我将从最大平分减少。在该问题的决策问题变体中,我们给出了图G和数k,并且要求将G的顶点分成两个相等大小的部分,使得两个部分之间的边数至少为k。 These slides通过从更一般的最大割限问题中减少来表明最大二分是NP难的,其中2部分不需要具有相同数量的顶点。

给定图G =(V,E)和数k,减少为:

  • 创建一个矩阵X,其中X [i] [j] = X [j] [i] = 1 if if(i,j)是G中的边,否则为0。
  • 选择N = | V | / 2。 (这将导致输出2组。)

在此构造的输入上为您的问题运行任何精确算法,并让此算法提供的最优解具有平均相似度y。 y =(y1 + y2)/ 2,其中y1和y2是每组的平均相似度。让我们在第一组z1中调用类似的无序对的数量(即,无序对(i,j),使得X [i] [j] = 1)。由于我们需要处理的唯一相似度得分是1和0,所以y1只是z1除以第一组中无序对的总数,正是(| V | / 2)(| V | / 2-1) )/ 2,所以y1 = 2 * z1 /((| V | / 2)(| V | / 2-1))。同样适用于y2。因此,就z1和z2而言,y =(z1 + z2)/((| V | / 2)(| V | / 2-1))。由于分母是常数,通过最大化组内平均相似度y,您的算法也最大化z1 + z2,也就是说,它最大化组内类似对的总数。

需要注意的关键是,在任何解决方案中,原始图的每个边都必须出现在其中一个组中或两个不同的组之间:即,对于任何解Y,nEdgesWithinAGroup(Y)+ nEdgesBetweenGroups( Y)= | E |,因此最小化组内边缘的数量与最大化组间边缘的数量相同。

由于假设你的问题的算法返回一个具有最小可能y的解,并且我们在上面已经确定这也意味着z1 + z2的最小可能值,而且后者意味着之间的最大可能数量 - 组边缘,它遵循两组之间的边数,| E | - z1 - z2,是最大可能的。因此,解决原始最大二分问题的剩余部分是将该值与给定的k值进行比较,如果是> = k,则返回YES,否则返回NO。

以上暗示,给定任何用于解决问题的多项式时间算法,以及NP-hard最大二分问题的任何实例,我们可以在多项式时间内构造问题的实例,解决问题并转换解决方案解决原始的最大二分问题 - 也就是说,它意味着我们可以在多项式时间内解决NP难问题。这意味着你的问题本身就是NP难的。

答案 1 :(得分:0)

如果我没有完全误解你的问题而你想在这里做一个糟糕的方式,那就是: 蛮力方法:

  1. 获取P选择(P / N)组合,其中P是元素数,N是要分区的组数。
  2. 计算1中返回的每个组合的“内部相似度”。
  3. 从2获得N.
  4. Python实现:

    def getValues(matrix):
        values=[]
        count=1
        while ((len(matrix)- count)>0):
            j= count
            for i in range(len(matrix)- count ):
                values.append(matrix[count-1][j ] )
                j+=1
            count+=1
        return values
    
    
    
    def c(arr, curr, end,k ,n , comb=[]):
        """get combinations for list length n and choose k elem"""
        if comb is None:
            comb = []
        elif n ==1 :
            comb = []
        if ((arr.count(1) is not k) and (curr < end)):
            tmparr= [ i for i in arr]
            tmparr[curr]= 1
            c(tmparr, curr+ 1 , end,k ,n + 1 , comb)
            tmparr[curr]= 0
            c(tmparr, curr+ 1 , end,k ,n + 1 , comb)
        if arr.count(1) ==k :
            comb.append(arr)
        if n is 1:
            return comb
    
    
    def combos(l, choose):
        """
        use this w/ c() to get combinations
        """
        arr = [1 for i in l]
        return c(arr,0 , len(l), choose,1 )
    
    
    def getComb(combos, elem):
        """
        EX. combos=[0,1,1] elem=["A","B","C"]
        return ["B","C"]
        """
        result= [ ]
        for i in combos:
            tmp= ""
            for j in range(len(i)):
                if i[j] is 1:
                    tmp+= elem[j]
            result.append(tmp)
        return result
    
    def subSum(sub,d):
        """
        EX. sub = "abc" then return value d["ab"]+d["ac"]+d["bc"]
        sub -- list of string elements
        d -- dictionary
        """
        if( len(sub) is 2):
            return d[sub[0]+ sub [1]]
        sum=0
        for i in range(len(sub)-1) :
            sum+=d [ sub[0]+ sub [i+1] ]
        return sum+ subSum(sub[1:],d)
    
    def contains(a,b):
        for i in a:
            if i in b:
                return True
        return False
    
    
    #**************INPUT HERE**************#
    # elements
    e = ["A","B", "C", "D", "E", "F"] # partition set into N
    N = 2
    
    matrix =[ [100,2,3,4,5,6],
        [ 2, 100,9,16,23 ,30] ,
        [ 44,22,100,11,5 ,2] ,
        [ 11 ,22,33,100, 44, 55],
        [1 ,6,7,13,100, 20 ],
        [1 ,1,2,3,5,100 ] ]
    #**************************************#
    
    
    if len(matrix) is len(e):
        p = getComb(combos(e,(int)(len( matrix)/N)),e)
        q = getComb(combos(e,2),e)
        values = getValues(matrix)
    
        # make lookup for subSum()
        d = {}
        for i in range(len(q)):
            d[q[i]]=values[i]
    
        result=[]
        for i in range(N):
            sums = [subSum(i, d) for i in p]
            m = min(sums)
            s = p[sums.index(m)]
            result.append(s)
            for i in p:
                if contains(s, i):
                    p.remove(i)
    
        print(result)  # this is the answer