/* * See Figure 11-2, "The Hungarian method", page 251. * * Corresponds to lines 26--27, 38--39. * Called by hm_pre_search() and hm_search(). */ static void hm_update_slack( hm_data *hm, int z ) { int k, tmp; for EACH_U( k ) { tmp = C( z, k ) - ALPHA( z ) - BETA( k ); if ( 0 <= tmp && tmp < SLACK( k ) ) { SLACK( k ) = tmp; /* * The following decrement and increment are necessary to maintain * the count[] array, which is not included in the original Figure * 11-2 implementation, and whose addition and purpose are described * above in hm_construct_auxiliary_graph(). */ if ( NHBOR( k ) != blank ) { --COUNT( NHBOR( k ) ); } ++COUNT( z ); NHBOR( k ) = z; } } }
void MatchGraph::SET_MATCH_BOUNDS () { long del; for (v=1; v <= U; ++v) { if (LINK[(int)v] < 0 || BASE[(int)v] != v) { NEXT_D[(int)v] = LAST_D; continue; } LINK[(int)v] = -LINK[(int)v]; i = v; while (i != DUMMYVERTEX) { Y[(int)i] -= DELTA; i = NEXTVTX[(int)i]; } f = MATE[(int)v]; if (f != DUMMYEDGE) { i = BEND(f); del = SLACK(f); while (i != DUMMYVERTEX) { Y[(int)i] -= del; i = NEXTVTX[(int)i]; } } NEXT_D[(int)v] = LAST_D; } }
/* * This function is for debugging purposes. It prints the algorithm's internal * state in a format similar to that of Example 11.1 (The matrix form of the * Hungarian method) beginning on page 252. * * The formatted output coded here is intended for small numbers. */ static void hm_print( hm_data *hm ) { int i, j, k; printf( "\n a\\b |" ); for EACH_U( j ) { printf( "%3d ", BETA( j ) ); } printf( "mate exposed label\n" ); printf( "-----+" ); for EACH_U( j ) { printf( "----" ); } printf( "------------------\n" ); for EACH_V( i ) { printf( " |\n %3d |", ALPHA( i ) ); for EACH_U( j ) { printf( "%3d ", C( i, j ) ); } printf( "%4d %7d %5d\n", MATE( i ), EXPOSED( i ), LABEL( i ) ); } printf( "\nslack" ); for EACH_U( j ) { printf( " %3d", SLACK( j ) == INT_MAX ? -1 : SLACK( j ) ); } printf( "\nnhbor" ); for EACH_U( j ) { printf( " %3d", NHBOR( j ) ); } printf( "\n\nA = { " ); for ( k = 0; k < A.size; ++k ) { printf( "(%d,%d) ", A.data[ k ].x, A.data[ k ].y ); } printf( "}\nQ = { " ); for ( k = 0; k < Q.size; ++k ) { printf( "%d ", Q.data[ k ] ); } printf( "}\n\n" ); }
/* * See Figure 11-2, "The Hungarian method", page 251. * * Corresponds to lines 12--17. */ static void hm_construct_auxiliary_graph( hm_data *hm ) { int i, j; A.size = 0; for EACH_V( i ) { EXPOSED( i ) = blank; LABEL( i ) = blank; /* * The following data structure is not included in the Figure 11-2 * pseudo-code implementation. It has been added to account for * "labeling" on certain vertices described within Example 11.1 that * would otherwise be missing from the Figure 11-2 implementation. * * count[v] for any v \in V is equal to the size of the set * { u \in U : nhbor[u] = v }. When this set is non-empty, v is * considered to be "labeled". The use of this new data structure is * only to complete the conditional check on "labeled" statuses when * updating alpha within "procedure modify". */ COUNT( i ) = 0; } for EACH_U( j ) { SLACK( j ) = INT_MAX; /* * The following initialization of nhbor[] is necessary for proper usage * of the count[] array, whose addition and purpose is described above. */ NHBOR( j ) = blank; } for EACH_V( i ) { for EACH_U( j ) { if ( ALPHA( i ) + BETA( j ) == C( i, j ) ) { if ( MATE( j ) == blank ) { EXPOSED( i ) = j; } else if ( i != MATE( j ) ) { add_arc( &A, i, MATE( j ) ); } } } } }
/* * See Figure 11-2, "The Hungarian method", page 252. * * Corresponds to "procedure modify". */ static bool hm_modify( hm_data *hm ) { int i, j, theta_one; /* * Determine theta_one. */ theta_one = INT_MAX; for EACH_U( j ) { if ( 0 < SLACK( j ) && SLACK( j ) < theta_one ) { theta_one = SLACK( j ); } } theta_one /= 2; /* * Update the dual variable alpha. */ for EACH_V( i ) { /* * The following conditional expression has been changed from its form * in Figure 11-2. Here, an additional check on the count[] array is * performed to account for a certain type of "labeling" that is * mentioned in the Example 11.1 walk-through but is omitted from the * Figure 11-2 implementation. * * See the comments provided near the initialization of count[] in the * function hm_construct_auxiliary_graph(). */ if ( LABEL( i ) != blank || COUNT( i ) > 0 ) { ALPHA( i ) += theta_one; } else { ALPHA( i ) -= theta_one; } } /* * Update the dual variable beta. */ for EACH_U( j ) { if ( SLACK( j ) == 0 ) { BETA( j ) -= theta_one; } else { BETA( j ) += theta_one; } } /* * Update slack and check for new admissible edges. */ for EACH_U( j ) { if ( SLACK( j ) > 0 ) { SLACK( j ) -= 2 * theta_one; if ( SLACK( j ) == 0 ) { if ( MATE( j ) == blank ) { EXPOSED( NHBOR( j ) ) = j; hm_augment( hm, NHBOR( j ) ); return false; /* goto endstage */ } else { /* * The following statement corresponds to a pseudo-code * command that should be removed from the else-clause of * the modify procedure in Figure 11-2. * * LABEL( MATE( j ) ) = NHBOR( j ); * * The inclusion of the above statement causes the arc * added in one of the next statements to never be considered * in following "search" sub-stages during this stage, and it * partially duplicates what would happen in these sub-stages * if the arc were to be considered there. The result of * inclusion is (often) non-optimality of the algorithm's * output. */ /* * The next statement corresponds to a pseudo-code command * (in the same else-clause) that should be modified * slightly. In Figure 11-2, this command "pushes" mate[ u ] * into Q when it should be "pushing" nhbor[ u ] instead. * This is because the purpose of this command is to ensure * that the soon-to-be-added arc will be considered in the * next "search" sub-stage, and consideration is dependent * upon the arc-tail, not the arc-head. */ stack_push( &Q, NHBOR( j ) ); /* Note modification */ add_arc( &A, NHBOR( j ), MATE( j ) ); } } } } return true; }