我试图在C中实现匈牙利算法。
我有矩阵:
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
我要到达必须找到覆盖所有零的最小行数的阶段(尽可能多地进行分配)。显然,通过检查,这是第1列和第3列以及第1行。
Wikipedia suggests the following method:
如果我按照上面的矩阵进行操作,我会得到:
35 0' 0 0
0' 30 0 5
55 5 0' 10
0 45 30 45
其中零素数是指定的零。然后,按照下面的维基百科说明,我标记第4行(未分配的零),第1列(带有未分配的零的col),然后是第2行(带有标记col的零的行)。
因此,这意味着命中所有零的最小行是:
+--------
|
+--------
|
但这并没有在(2, 3)
达到零。相关的C代码:
for (i = 0; i < M->size; i++) {
for (j = 0; j < M->size; j++) {
if (M->values[i][j] == 0) {
if (assigned_cols[j] == 0) {
assigned_cols[j] = 1; // We've assigned something in this col
assigned_rows[i] = 1; // We've assigned something in this row.
marked_rows[i] = 0;
total--;
break; // Go to the next row
} else {
marked_cols[j] = 1; // Then there exists a zero in this col in an unassigned row
mark_col(M, j); // marks all elements in column j
total++;
}
}
}
}
此代码选择哪些零为素数(指定零)。
然后,此代码标记在新标记的列中具有分配的所有行:
for (i = 0; i < M->size; i++) {
if (marked_cols[i] == 1) {
for (j = 0; j < M->size; j++) {
//iterating through rows
if (M->values[j][i] == 0) {
// then (j,i) is a zero in a marked col
// mark the row
if (marked_rows[j] != 1) {
total++;
marked_rows[j] = 1;
}
break; // no need to continue more
}
}
}
}
但是这个(和维基百科的解释)在我的矩阵上面失败了。怎么样?
答案 0 :(得分:5)
维基百科缺乏对算法的解释,分配将在最后一步完成!
第0步
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
步骤1-2 所有行 - 列至少有一个0,因此步骤1使数组保持相同的
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
第3步 矩阵中的所有零必须通过尽可能少的行和/或列标记来覆盖
- - - -
| |
| |
| |
请注意,目前尚未完成任务,您需要涵盖all zeros
。你的封面留下零(2,3)未覆盖!!
现在取min未包含的元素,例如5(在位置(2,4)处取5)
- 减少(按5)所有未覆盖的元素 - 增加(按5)所有由两条线交叉的元素 - 保持不变 所以数组:
40 0 5 0
0 25 0 0
55 0 0 5
0 40 30 40
现在再次检查所需的最小行数:现在需要4行(等于n = 4行数组,所以我们停止)。
最后分配: 从只有一个零的行开始,肯定会分配:
40 0 5 _
0 25 _ 0
55 _ 0 5
_ 40 30 40
存在多个分配(我使用_进行分配)。
更具体地说,我们获得了两项任务:(上述一项,总费用为5)和:
40 _ 5 0
0 25 0 _
55 0 _ 5
_ 40 30 40
还有成本5!
基于评论,似乎我没有得到op所要求的确切部分所以我将回答这个具体部分,保留上述算法的一般描述。
错误(由于维基百科描述错误)在这里:
其中零素数是指定的零。然后,遵循维基百科 下面的说明,我标记第4行(未分配的零),第1列(col with 未分配的零),然后是第2行(标记为col的行为零)。
直到现在完全同意但是......它还没有完成!!!
正确标记row2时,您需要转到第2步(维基百科) 并再次检查具有零的列,在这种情况下,列3应该 也被标记,这也导致第3行也被标记(由于在新标记的第3列中分配了零)和 你停下来(不应该标记其他行或列)!!
总体而言,标记的列和行:
+ +
35 0' 0 0
0' 30 0 5 +
55 5 0' 10 +
0 45 30 45 +
通过选择标记的列和未标记的行来获得的行:
- - - -
| |
| |
| |
这是答案的第一部分中描述的正确的一个,并导致下一阶段的正确结果(也在上面解释)。
在 mathstackexchange 上可以找到一个非常相似的帖子: mathstackexchange :
finding the minimum number of lines to cover all zeros in an assignment probem