Content deleted Content added
→Matrix formulation: removed unnecessary double permutation (due to the cyclic invariance of the trace, the two permutations can be combined into one – only the workers or the jobs need to be permuted, not both) |
→Matrix interpretation: Revise section. The logical structure is clearer but I use GOTO and (Else branch continued) in Step 4 so that could probably be simplified somehow. |
||
Line 88:
==Matrix interpretation==
Given {{mvar|n}} workers and tasks,
:{{aligned table|cols=4|class=wikitable
| a<sub>1</sub> | a<sub>2</sub> | a<sub>3</sub> | a<sub>4</sub>
| b<sub>1</sub> | b<sub>2</sub> | b<sub>3</sub> | b<sub>4</sub>
| c<sub>1</sub> | c<sub>2</sub> | c<sub>3</sub> | c<sub>4</sub>
| d<sub>1</sub> | d<sub>2</sub> | d<sub>3</sub> | d<sub>4</sub>}}
where a, b, c and d are
The problem is equivalent to assigning each worker a unique task such that the total penalty is minimized. Note that each task can only be worked on by one worker.
===Step 1===
'''For each row, its minimum element is subtracted from every element in that row.''' This causes all elements to have non-negative values. Therefore, an assignment with a total penalty of 0 is by definition a minimum assignment.
This also leads to at least one zero in each row. As such, a naive greedy algorithm can attempt to assign all workers a task with a penalty of zero. This is illustrated below.
:{{aligned table|cols=4|class=wikitable
| 0 | a<sub>2</sub> | a<sub>3</sub> | a<sub>4</sub>
| b<sub>1</sub> | b<sub>2</sub> | b<sub>3</sub> | 0
| c<sub>1</sub> | 0 | c<sub>3</sub> | c<sub>4</sub>
| d<sub>1</sub> | d<sub>2</sub> | 0 | d<sub>4</sub>}}
Worst-case there are {{mvar|n}}! combinations to try, since multiple zeroes can appear in a row if multiple elements are the minimum. So at some point this naive algorithm should be short circuited.
▲The zeros that are indicated as 0 are the assigned tasks.
===Step 2===
Line 125 ⟶ 120:
Sometimes it may turn out that the matrix at this stage cannot be used for assigning, as is the case for the matrix below.
:{{aligned table|cols=4|class=
| 0 | a<sub>2</sub> | 0 | a<sub>4</sub>
| b<sub>1</sub> | 0 | b<sub>3</sub> | 0
| 0 | c<sub>2</sub> | c<sub>3</sub> | c<sub>4</sub>
| 0 | d<sub>2</sub> | d<sub>3</sub> | d<sub>4</sub>}}
To overcome this, we repeat the above procedure for all columns (i.e. '''the minimum element in each column is subtracted from all the elements in that column''') and then check if an assignment with penalty 0 is possible.▼
▲To overcome this, we repeat the above procedure for all columns (i.e. '''the minimum element in each column is subtracted from all the elements in that column''') and then check if an assignment is possible.
In most situations this will give the result, but if it is still not possible then we need to keep going.
Line 143 ⟶ 132:
===Step 3===
'''All zeros in the matrix must be covered by marking as few rows and/or columns as possible.'''
We could end with another assignment if we choose another ordering of the rows and columns.
:{{aligned table|cols=4|class=
| 0* | a<sub>2</sub> | 0 | a<sub>4</sub>
| b<sub>1</sub> | 0* | b<sub>3</sub> | 0
| 0 | c<sub>2</sub> | c<sub>3</sub> | c<sub>4</sub>
| 0 | d<sub>2</sub> | d<sub>3</sub> | d<sub>4</sub>}}
===Step 4===
Cover all columns containing a (starred) zero.
:{|class="wikitable" style="text-align:center"
|- style="background: white"
|× ||× || || ||
|-
|style="background:lightgrey"| 0*||style="background:lightgrey"|
|style="background: white"|
|-
|style="background:lightgrey"|
|style="background: white"|
|-
|style="background:lightgrey"| 0 ||style="background:lightgrey"|
|style="background: white"|
|-
|style="background:lightgrey"| 0 ||style="background:lightgrey"|
|}
* If the zero is on the same row as a starred zero, cover the corresponding row, and uncover the column of the starred zero. * Then, GOTO "Find a non-covered zero and prime it."
** Here, the second zero of Row 1 is uncovered. Because there is another zero starred on Row 1, we cover Row 1 and uncover Column 1. ** Then, the second zero of Row 2 is uncovered. We cover Row 2 and uncover Column 2.
:{|class="wikitable" style="text-align:center"
Line 189 ⟶ 178:
|| ||× || || ||
|- style="background:lightgrey"
| 0*||
|style="background: white"|×
|-
|
|style="background: white"|
|-
|| 0 ||style="background:lightgrey"|
|style="background: white"|
|-
|| 0 ||style="background:lightgrey"|
|style="background: white"|
|}
Line 206 ⟶ 195:
|| || || || ||
|- style="background:lightgrey"
| 0*||
|style="background: white"|×
|- style="background:lightgrey"
|
|style="background: white"|×
|-
|| 0 ||
|style="background: white"|
|-
|| 0 ||
|style="background: white"|
|}
*
*
*
The zero on Row 3 is uncovered. We
:{|class="wikitable" style="text-align:center"
|- style="background: white"
|| || || || ||
|- style="background:lightgrey"
| <span style="color:red">0*</span> ||
|style="background: white"|×
|- style="background:lightgrey"
|
|style="background: white"|×
|-
|| <span style="color:red">0'</span> ||
|style="background: white"|
|-
|| 0 ||
|style="background: white"|
|}
*(Else branch continued) For all zeros encountered during the path, star primed zeros and unstar starred
**As the path begins and ends by a primed zero when swapping starred zeros, we have assigned one more zero.
:{|class="wikitable" style="text-align:center"
|-
| 0 ||
|-
|
|-
|| 0*||
|-
|| 0 ||
|}
*(Else branch continued) Unprime all primed zeroes and uncover all lines.
* Repeat the previous steps (continue looping until the above "skip to step 5" is reached).
**
:{|class="wikitable" style="text-align:center"
|- style="background: white"
||× || ||× || ||
|-
|style="background:lightgrey"| 0 ||
|style="background: white"|
|- style="background:lightgrey"
|
|style="background: white"|×
|-
|style="background:lightgrey"| 0*||
|style="background: white"|
|-
|style="background:lightgrey"| 0 ||
|style="background: white"|
|}
Line 275 ⟶ 266:
The aforementioned detailed description is ''just one way'' to draw the minimum number of lines to cover all the 0s. Other methods work as well.
===Step
'''Find the lowest uncovered value. Subtract this from every unmarked element and add it to every element covered by two lines.'''
Line 281 ⟶ 272:
This is equivalent to subtracting a number from all rows which are not covered and adding the same number to all columns which are covered. These operations do not change optimal assignments.
Repeat steps
If following this specific version of the algorithm, the starred zeros form the minimum assignment.
From Kőnig's theorem,<ref>[[K%C5%91nig%27s theorem (graph theory)]] Konig's theorem</ref> the minimum number of lines (minimum Vertex cover<ref>[[Vertex cover]] minimum vertex cover</ref>) will be {{mvar|n}} (the size of maximum matching<ref>[[Matching (graph theory)]] matching</ref>). Thus, when {{mvar|n}} lines are required, minimum cost assignment can be found by looking at only zeroes in the matrix.
==Bibliography==
* R.E. Burkard, M. Dell'Amico, S. Martello: ''Assignment Problems'' (Revised reprint). SIAM, Philadelphia (PA.) 2012. {{ISBN|978-1-61197-222-1}}
|