我在坐标系中绘制了两组点。一组中的每个点必须与另一组中的至少一个点匹配,其方式是通过连接这些点绘制的线的长度之和应该尽可能低。为了说清楚,线条图只是一个抽象,实际输出只是必须匹配的点对。
我见过this question关于类似问题,但在我的情况下没有单链接限制,因为这些集可能有不同的大小。有没有描述这种情况的问题?更具体地说,我可以使用什么算法来解决这个问题,假设每个集合最多可以有10个点?
答案 0 :(得分:1)
您可以将此建模为网络流量问题。
通过在第一组中的每个点处具有1的源,并且在第二组中的每个点处具有1的接收器,以及针对任何剩余容量的额外节点“dest”,任何有效流将始终连接每个点。
根据点之间的距离在成本点之间建立边缘。
到目前为止,我们有一个网络,其解决方案是第1组到第2组的最低成本匹配(即每个点都有一个链接)。
要允许多个链接,您只需添加以下内容:
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。这解决了算法“贪婪”可能引起的最简单问题之一。