有一个方形二进制矩阵,表示二分图中的连接。问题是:是否存在所有行与列的一对一映射? (要清楚,如果我使用的语言不对,完全连接的图表满足此要求,因为我们不仅限于一对一的映射。)
我写了以下内容。有没有一种可笑的更快的方法来实现这个目标?
/* Is there a one-to-one mapping possible with the given bipartite graph?
input: graph[a][b] = connected (1) or not (0)
return: 0=no 1=yes */
int one_to_one(int graph[SIZE][SIZE], int rows_checked /* =0 */, int col_chosen /* =0 */)
{
int my_graph[SIZE][SIZE], i, j, retval;
memcpy(my_graph, graph, sizeof(graph[0][0]) * SIZE * SIZE);
if (rows_checked > 0)
for (i=rows_checked; i<SIZE; i++)
my_graph[i][col_chosen] = -1; /* flag for "this column done" */
retval=1;
for (i=0; i<SIZE; i++) {
if (my_graph[rows_checked][i] == -1)
continue;
retval=0;
if (my_graph[rows_checked][i] == 1)
if (one_to_one(my_graph, rows_checked+1, i))
return 1;
}
return retval;
}
答案 0 :(得分:1)
我假设在你的表示中,你的意思是你有一个二分图,其中两个“边”具有相同数量的节点,而图[A] [B]表示存在来自节点A的连接如果每个分区中的所有节点都布置在一条垂直线上,则在“右侧”的“左侧”到节点B上。
如果图表稀疏,你的算法实际上并不坏,而且它具有简单的优点。
对于更密集的图形,它是指数级的,如果您愿意为其编写代码,则可以做得更好。如果将源节点添加到连接到所有“左”节点的图形,并将接收器连接到所有“右”节点,并将容量1分配给所有边缘(包括新节点),则从源到源的最大网络流量当且仅当存在一对一配对时,sink等于SIZE。如果使用诸如Ford-Fulkurson之类的算法来计算流量,则每个循环将连接另一对节点,根据需要重新排列现有连接以实现这一点,直到不再可能。运行时间将在SIZE ^ 3范围内。
这也可以直接用二分图表示和重新排列匹配对来实现,但我发现如果你把它构建为一个网络流程实现来启动然后从那里重构,我觉得最容易理解。如果在二分图中找到最大数量的匹配对,请参阅the "Maximum matchings in bipartite graphs" section of the Wikipedia page on graph matching problems,了解更为一般的问题,这是基于流的解决方案实际解决的问题。
如果你真的想要速度,看看我尚未实施的Hopcroft-Kamp,我现在正在阅读自己。页面链接表明它具有SIZE ^(5/2)的最坏情况(在本例中),并且在优化稀疏图形方面与Ford-Fulkerson一样好或更好。