git
/
linear-assignment.c
207 строк · 4.1 Кб
1/*
2* Based on: Jonker, R., & Volgenant, A. (1987). <i>A shortest augmenting path
3* algorithm for dense and sparse linear assignment problems</i>. Computing,
4* 38(4), 325-340.
5*/
6#include "git-compat-util.h"7#include "linear-assignment.h"8
9#define COST(column, row) cost[(column) + column_count * (row)]10
11/*
12* The parameter `cost` is the cost matrix: the cost to assign column j to row
13* i is `cost[j + column_count * i].
14*/
15void compute_assignment(int column_count, int row_count, int *cost,16int *column2row, int *row2column)17{
18int *v, *d;19int *free_row, free_count = 0, saved_free_count, *pred, *col;20int i, j, phase;21
22if (column_count < 2) {23memset(column2row, 0, sizeof(int) * column_count);24memset(row2column, 0, sizeof(int) * row_count);25return;26}27
28memset(column2row, -1, sizeof(int) * column_count);29memset(row2column, -1, sizeof(int) * row_count);30ALLOC_ARRAY(v, column_count);31
32/* column reduction */33for (j = column_count - 1; j >= 0; j--) {34int i1 = 0;35
36for (i = 1; i < row_count; i++)37if (COST(j, i1) > COST(j, i))38i1 = i;39v[j] = COST(j, i1);40if (row2column[i1] == -1) {41/* row i1 unassigned */42row2column[i1] = j;43column2row[j] = i1;44} else {45if (row2column[i1] >= 0)46row2column[i1] = -2 - row2column[i1];47column2row[j] = -1;48}49}50
51/* reduction transfer */52ALLOC_ARRAY(free_row, row_count);53for (i = 0; i < row_count; i++) {54int j1 = row2column[i];55if (j1 == -1)56free_row[free_count++] = i;57else if (j1 < -1)58row2column[i] = -2 - j1;59else {60int min = COST(!j1, i) - v[!j1];61for (j = 1; j < column_count; j++)62if (j != j1 && min > COST(j, i) - v[j])63min = COST(j, i) - v[j];64v[j1] -= min;65}66}67
68if (free_count ==69(column_count < row_count ? row_count - column_count : 0)) {70free(v);71free(free_row);72return;73}74
75/* augmenting row reduction */76for (phase = 0; phase < 2; phase++) {77int k = 0;78
79saved_free_count = free_count;80free_count = 0;81while (k < saved_free_count) {82int u1, u2;83int j1 = 0, j2, i0;84
85i = free_row[k++];86u1 = COST(j1, i) - v[j1];87j2 = -1;88u2 = INT_MAX;89for (j = 1; j < column_count; j++) {90int c = COST(j, i) - v[j];91if (u2 > c) {92if (u1 < c) {93u2 = c;94j2 = j;95} else {96u2 = u1;97u1 = c;98j2 = j1;99j1 = j;100}101}102}103if (j2 < 0) {104j2 = j1;105u2 = u1;106}107
108i0 = column2row[j1];109if (u1 < u2)110v[j1] -= u2 - u1;111else if (i0 >= 0) {112j1 = j2;113i0 = column2row[j1];114}115
116if (i0 >= 0) {117if (u1 < u2)118free_row[--k] = i0;119else120free_row[free_count++] = i0;121}122row2column[i] = j1;123column2row[j1] = i;124}125}126
127/* augmentation */128saved_free_count = free_count;129ALLOC_ARRAY(d, column_count);130ALLOC_ARRAY(pred, column_count);131ALLOC_ARRAY(col, column_count);132for (free_count = 0; free_count < saved_free_count; free_count++) {133int i1 = free_row[free_count], low = 0, up = 0, last, k;134int min, c, u1;135
136for (j = 0; j < column_count; j++) {137d[j] = COST(j, i1) - v[j];138pred[j] = i1;139col[j] = j;140}141
142j = -1;143do {144last = low;145min = d[col[up++]];146for (k = up; k < column_count; k++) {147j = col[k];148c = d[j];149if (c <= min) {150if (c < min) {151up = low;152min = c;153}154col[k] = col[up];155col[up++] = j;156}157}158for (k = low; k < up; k++)159if (column2row[col[k]] == -1)160goto update;161
162/* scan a row */163do {164int j1 = col[low++];165
166i = column2row[j1];167u1 = COST(j1, i) - v[j1] - min;168for (k = up; k < column_count; k++) {169j = col[k];170c = COST(j, i) - v[j] - u1;171if (c < d[j]) {172d[j] = c;173pred[j] = i;174if (c == min) {175if (column2row[j] == -1)176goto update;177col[k] = col[up];178col[up++] = j;179}180}181}182} while (low != up);183} while (low == up);184
185update:186/* updating of the column pieces */187for (k = 0; k < last; k++) {188int j1 = col[k];189v[j1] += d[j1] - min;190}191
192/* augmentation */193do {194if (j < 0)195BUG("negative j: %d", j);196i = pred[j];197column2row[j] = i;198SWAP(j, row2column[i]);199} while (i1 != i);200}201
202free(col);203free(pred);204free(d);205free(v);206free(free_row);207}
208