匹配两个不同大小的集合中的每个点,总线长度最小

时间:2014-02-08 16:50:52

标签: algorithm

我在坐标系中绘制了两组点。一组中的每个点必须与另一组中的至少一个点匹配,其方式是通过连接这些点绘制的线的长度之和应该尽可能低。为了说清楚,线条图只是一个抽象,实际输出只是必须匹配的点对。

我见过this question关于类似问题,但在我的情况下没有单链接限制,因为这些集可能有不同的大小。有没有描述这种情况的问题?更具体地说,我可以使用什么算法来解决这个问题,假设每个集合最多可以有10个点?

2 个答案:

答案 0 :(得分:1)

算法

您可以将此建模为网络流量问题。

通过在第一组中的每个点处具有1的源,并且在第二组中的每个点处具有1的接收器,以及针对任何剩余容量的额外节点“dest”,任何有效流将始终连接每个点。

根据点之间的距离在成本点之间建立边缘。

到目前为止,我们有一个网络,其解决方案是第1组到第2组的最低成本匹配(即每个点都有一个链接)。

要允许多个链接,您只需添加以下内容:

  1. 在set2和'dest'中的每个点之间添加0个权重边(这允许第2组中的点多重连接)
  2. 在'dest'和set2中的每个点之间添加0个权重边(这允许集合1中的点多重连接)
  3. 使用Networkx的示例Python代码

    import networkx as nx
    import random
    
    G=nx.DiGraph()
    
    set1=['A','B','C','D','E','F','G','H','I']
    set2=['a','b','c']
    # Assume set1 > set2 (or swap sets)
    assert len(set1)>=len(set2)
    
    G.add_node('dest',demand=len(set1)-len(set2))
    A=[]
    for person in set1:
            G.add_node(person,demand=-1)
            G.add_edge('dest',person,weight=0)
            for project in set2:
                    cost = random.randint(1,10) # Assign appropriate costs here
                    G.add_edge(person,project,weight=cost) # Edge taken if person does this project
    
    for project in set2:
            G.add_node(project,demand=1)
            G.add_edge(project,'dest',weight=0)
    
    flowdict = nx.min_cost_flow(G)
    for person in set1:
            for project,flow in flowdict[person].items():
                    if flow:
                            print person,'->',project
    

答案 1 :(得分:0)

您可以使用离散优化方法(Integer Programming)。

我们有两个大小为X的集合A和大小为Y的B.这意味着最多的X * Y个链接,每个都由一个布尔变量描述:L(i,j)= L(Y * i +如果节点A(i)和B(j)被链接,则j)为1,否则为0。如果X = Y = 10,我们可以将链接L(7,3)写为L73。

我们可以像这样重写这个问题:

节点A(i)至少有一个链接:X(比方说,十)标准,i从0到X-1,每个都包含Y个分量:

    L(i,0)+L(i,1)+L(i,2)+...+L(i,Y-1) >= 1

Node B(j) has at least one link, and there are Y criteria made up of X components:

    L(0,j)+L(1,j)+L(2,j)+...+L(X-1,j) >= 1

最低成本要求变为:

cost = SUM(C(0,0)*L(0,0)+C(0,1)*L(0,1)+...+C(9,9)*L(9,9) 

通过这些约定,我们可以轻松地为ILP问题构建矩阵,可以将其传递给我们最喜欢的ILP求解包或库(C,Java,Python,甚至PHP)。

====

一个独立的“贪婪”算法保证找到最小值,但相当快, 应该给出合理的结果,除非你提供病理数据设置,是:

- connect all points in the smaller set, each to its nearest point in the other set.
- connect all unconnected points remaining in the larger set, each to its
  nearest point in the first set, whether it's already connected or not.

作为优化,您可以枚举较大数据集中的点;如果其中一个(比如说A)单独连接到第一个数据集中的一个点(比如B),它是多重连接的,并且不是它最近的邻居C,你可以将链接从A-B切换到A-C。这解决了算法“贪婪”可能引起的最简单问题之一。