# Hungarian Algorithm for Assignment Problem | Set 1 (Introduction)

Let there be n agents and n tasks. Any agent can be assigned to perform any task, incurring some cost that may vary depending on the agent-task assignment. It is required to perform all tasks by assigning exactly one agent to each task and exactly one task to each agent in such a way that the total cost of the assignment is minimized. Example: You work as a manager for a chip manufacturer, and you currently have 3 people on the road meeting clients. Your salespeople are in Jaipur, Pune and Bangalore, and you want them to fly to three other cities: Delhi, Mumbai and Kerala. The table below shows the cost of airline tickets in INR between the cities: The question: where would you send each of your salespeople in order to minimize fair? Possible assignment: Cost = 11000 INR Other Possible assignment: Cost = 9500 INR and this is the best of the 3! possible assignments. Brute force solution is to consider every possible assignment implies a complexity of ?(n!). The Hungarian algorithm, aka Munkres assignment algorithm, utilizes the following theorem for polynomial runtime complexity (worst case O(n3)) and guaranteed optimality: If a number is added to or subtracted from all of the entries of any one row or column of a cost matrix, then an optimal assignment for the resulting cost matrix is also an optimal assignment for the original cost matrix. We reduce our original weight matrix to contain zeros, by using the above theorem. We try to assign tasks to agents such that each agent is doing only one task and the penalty incurred in each case is zero. Core of the algorithm (assuming square matrix):

1. For each row of the matrix, find the smallest element and subtract it from every element in its row.
2. Do the same (as step 1) for all columns.
3. Cover all zeros in the matrix using minimum number of horizontal and vertical lines.
4. Test for Optimality: If the minimum number of covering lines is n, an optimal assignment is possible and we are finished. Else if lines are lesser than n, we havenâ€™t found the optimal assignment, and must proceed to step 5.
5. Determine the smallest entry not covered by any line. Subtract this entry from each uncovered row, and then add it to each covered column. Return to step 3.

Try it before moving to see the solution

Explanation for above simple example:

```
Below is the cost matrix of example given in above diagrams.
2500  4000  3500
4000  6000  3500
2000  4000  2500

Step 1: Subtract minimum of every row.
2500, 3500 and 2000 are subtracted from rows 1, 2 and
3 respectively.

0   1500  1000
500  2500   0
0   2000  500

Step 2: Subtract minimum of every column.
0, 1500 and 0 are subtracted from columns 1, 2 and 3
respectively.

0    0   1000
500  1000   0
0   500  500

Step 3: Cover all zeroes with minimum number of
horizontal and vertical lines.

Step 4:  Since we need 3 lines to cover all zeroes,
we have found the optimal assignment.
2500  4000  3500
4000  6000  3500
2000  4000  2500

So the optimal cost is 4000 + 3500 + 2000 = 9500```

An example that doesn’t lead to optimal value in first attempt: In the above example, the first check for optimality did give us solution. What if we the number covering lines is less than n.

```
cost matrix:
1500  4000  4500
2000  6000  3500
2000  4000  2500

Step 1: Subtract minimum of every row.
1500, 2000 and 2000 are subtracted from rows 1, 2 and
3 respectively.

0    2500  3000
0    4000  1500
0    2000   500

Step 2: Subtract minimum of every column.
0, 2000 and 500 are subtracted from columns 1, 2 and 3
respectively.

0     500  2500
0    2000  1000
0      0      0

Step 3: Cover all zeroes with minimum number of
horizontal and vertical lines.

Step 4:  Since we only need 2 lines to cover all zeroes,
we have NOT found the optimal assignment.

Step 5:  We subtract the smallest uncovered entry
from all uncovered rows. Smallest entry is 500.
-500    0   2000
-500  1500   500
0     0      0

Then we add the smallest entry to all covered columns, we get
0     0   2000
0   1500   500
500    0      0

Now we return to Step 3:. Here we cover again using
lines. and go to Step 4:. Since we need 3 lines to
cover, we found the optimal solution.
1500  4000  4500
2000  6000  3500
2000  4000  2500

So the optimal cost is 4000 + 2000 + 2500 = 8500```

## C++

 `#include` `using` `namespace` `std;`     `class` `Solution {` `  ``public``:` `  `  `    ``int` `cost[31][31]; ``//cost matrix` `    ``int` `n, max_match; ``//n workers and n jobs` `    ``int` `lx[31], ly[31]; ``//labels of X and Y parts` `    ``int` `xy[31]; ``//xy[x] - vertex that is matched with x,` `    ``int` `yx[31]; ``//yx[y] - vertex that is matched with y` `    ``bool` `S[31], T[31]; ``//sets S and T in algorithm` `    ``int` `slack[31]; ``//as in the algorithm description` `    ``int` `slackx[31]; ``//slackx[y] such a vertex, that` `    ``int` `prev_ious[31]; ``//array for memorizing alternating p` `  `  `    ``void` `init_labels()` `    ``{` `        ``memset``(lx, 0, ``sizeof``(lx));` `        ``memset``(ly, 0, ``sizeof``(ly));` `        ``for` `(``int` `x = 0; x < n; x++)` `        ``for` `(``int` `y = 0; y < n; y++)` `        ``lx[x] = max(lx[x], cost[x][y]);` `    ``}` `    `  `     `  `    ``void` `update_labels()` `    ``{` `        ``int` `x, y;` `        ``int` `delta = 99999999; ``//init delta as infinity` `        ``for` `(y = 0; y < n; y++) ``//calculate delta using slack` `            ``if` `(!T[y])` `                ``delta = min(delta, slack[y]);` `        ``for` `(x = 0; x < n; x++) ``//update X labels` `            ``if` `(S[x])` `                ``lx[x] -= delta;` `        ``for` `(y = 0; y < n; y++) ``//update Y labels` `            ``if` `(T[y])` `                ``ly[y] += delta;` `        ``for` `(y = 0; y < n; y++) ``//update slack array` `            ``if` `(!T[y])` `                ``slack[y] -= delta;` `    ``}` `    `  `    `  `    ``void` `add_to_tree(``int` `x, ``int` `prev_iousx) ` `    ``//x - current vertex,prev_iousx - vertex from X before x in the alternating path,` `    ``//so we add edges (prev_iousx, xy[x]), (xy[x], x)` `    ``{` `        ``S[x] = ``true``; ``//add x to S` `        ``prev_ious[x] = prev_iousx; ``//we need this when augmenting` `        ``for` `(``int` `y = 0; y < n; y++) ``//update slacks, because we add new vertex to S` `            ``if` `(lx[x] + ly[y] - cost[x][y] < slack[y])` `            ``{` `                ``slack[y] = lx[x] + ly[y] - cost[x][y];` `                ``slackx[y] = x;` `            ``}` `    ``}` `    `  `    `  `    `  `    ``void` `augment() ``//main function of the algorithm` `    ``{` `        ``if` `(max_match == n) ``return``; ``//check whether matching is already perfect` `        ``int` `x, y, root; ``//just counters and root vertex` `        ``int` `q[31], wr = 0, rd = 0; ``//q - queue for bfs, wr,rd - write and read` `        ``//pos in queue` `        ``memset``(S, ``false``, ``sizeof``(S)); ``//init set S` `        ``memset``(T, ``false``, ``sizeof``(T)); ``//init set T` `        ``memset``(prev_ious, -1, ``sizeof``(prev_ious)); ``//init set prev_ious - for the alternating tree` `        `  `        ``for` `(x = 0; x < n; x++) ``//finding root of the tree` `        ``{` `            ``if` `(xy[x] == -1)` `            ``{` `                ``q[wr++] = root = x;` `                ``prev_ious[x] = -2;` `                ``S[x] = ``true``;` `                ``break``;` `            ``}` `        ``}` `        `  `        ``for` `(y = 0; y < n; y++) ``//initializing slack array` `        ``{` `            ``slack[y] = lx[root] + ly[y] - cost[root][y];` `            ``slackx[y] = root;` `        ``}` `        `  `        ``//second part of augment() function` `        ``while` `(``true``) ``//main cycle` `        ``{` `            ``while` `(rd < wr) ``//building tree with bfs cycle` `            ``{` `                ``x = q[rd++]; ``//current vertex from X part` `                ``for` `(y = 0; y < n; y++) ``//iterate through all edges in equality graph` `                    ``if` `(cost[x][y] == lx[x] + ly[y] && !T[y])` `                    ``{` `                        ``if` `(yx[y] == -1) ``break``; ``//an exposed vertex in Y found, so` `                                                ``//augmenting path exists!` `                            ``T[y] = ``true``; ``//else just add y to T,` `                        ``q[wr++] = yx[y]; ``//add vertex yx[y], which is matched` `                        ``//with y, to the queue` `                        ``add_to_tree(yx[y], x); ``//add edges (x,y) and (y,yx[y]) to the tree` `                    ``}` `                ``if` `(y < n)` `                    ``break``; ``//augmenting path found!` `            ``}` `            ``if` `(y < n)` `                ``break``; ``//augmenting path found!` `            `  `            ``update_labels(); ``//augmenting path not found, so improve labeling` `            `  `            ``wr = rd = 0; ` `            ``for` `(y = 0; y < n; y++) ` `            ``//in this cycle we add edges that were added to the equality graph as a` `            ``//result of improving the labeling, we add edge (slackx[y], y) to the tree if` `            ``//and only if !T[y] && slack[y] == 0, also with this edge we add another one` `            ``//(y, yx[y]) or augment the matching, if y was exposed` `            ``if` `(!T[y] && slack[y] == 0)` `            ``{` `                ``if` `(yx[y] == -1) ``//exposed vertex in Y found - augmenting path exists!` `                ``{` `                    ``x = slackx[y];` `                    ``break``;` `                ``}` `                ``else` `                ``{` `                    ``T[y] = ``true``; ``//else just add y to T,` `                    ``if` `(!S[yx[y]]) ` `                    ``{` `                        ``q[wr++] = yx[y]; ``//add vertex yx[y], which is matched with` `                        ``//y, to the queue` `                        ``add_to_tree(yx[y], slackx[y]); ``//and add edges (x,y) and (y,` `                        ``//yx[y]) to the tree` `                    ``}` `                ``}` `            ``}` `            ``if` `(y < n) ``break``; ``//augmenting path found!` `        ``}` `        `  `        ``if` `(y < n) ``//we found augmenting path!` `        ``{` `            ``max_match++; ``//increment matching` `            ``//in this cycle we inverse edges along augmenting path` `            ``for` `(``int` `cx = x, cy = y, ty; cx != -2; cx = prev_ious[cx], cy = ty)` `            ``{` `                ``ty = xy[cx];` `                ``yx[cy] = cx;` `                ``xy[cx] = cy;` `            ``}` `            ``augment(); ``//recall function, go to step 1 of the algorithm` `        ``}` `    ``}``//end of augment() function` `     `  `    ``int` `hungarian()` `    ``{` `        ``int` `ret = 0; ``//weight of the optimal matching` `        ``max_match = 0; ``//number of vertices in current matching` `        ``memset``(xy, -1, ``sizeof``(xy)); ` `        ``memset``(yx, -1, ``sizeof``(yx));` `        ``init_labels(); ``//step 0` `        ``augment(); ``//steps 1-3` `        `  `        ``for` `(``int` `x = 0; x < n; x++) ``//forming answer there` `            ``ret += cost[x][xy[x]];` `    `  `        ``return` `ret;` `    ``}` `    `  `    ``int` `assignmentProblem(``int` `Arr[], ``int` `N) {` `        `  `        ``n = N;` `        ``for``(``int` `i=0; i

## Java

 `// Java Equivalent:` `import` `java.util.*;` `public`  `class` `Solution {` `  ``public` `static` `int` `n;` `  ``public` `static` `int` `cost[][]; ``//cost matrix` `  ``public` `static` `int` `max_match; ``//n workers and n jobs` `  ``public` `static` `int` `lx[], ly[]; ``//labels of X and Y parts` `  ``public` `static` `int` `xy[]; ``//xy[x] - vertex that is matched with x,` `  ``public` `static` `int` `yx[]; ``//yx[y] - vertex that is matched with y` `  ``public` `static` `boolean` `S[], T[]; ``//sets S and T in algorithm` `  ``public` `static` `int` `slack[]; ``//as in the algorithm description` `  ``public` `static` `int` `slackx[]; ``//slackx[y] such a vertex, that` `  ``public` `static` `int` `prev_ious[]; ``//array for memorizing alternating p`   `  ``public` `static` `void` `init_labels()` `  ``{` `    ``Arrays.fill(lx, ``0``);` `    ``Arrays.fill(ly, ``0``);` `    ``for` `(``int` `x = ``0``; x < n; x++)` `      ``for` `(``int` `y = ``0``; y < n; y++)` `        ``lx[x] = Math.max(lx[x], cost[x][y]);` `  ``}`     `  ``public` `static` `void` `update_labels()` `  ``{` `    ``int` `x, y;` `    ``int` `delta = ``99999999``; ``//init delta as infinity` `    ``for` `(y = ``0``; y < n; y++) ``//calculate delta using slack` `      ``if` `(!T[y])` `        ``delta = Math.min(delta, slack[y]);` `    ``for` `(x = ``0``; x < n; x++) ``//update X labels` `      ``if` `(S[x])` `        ``lx[x] -= delta;` `    ``for` `(y = ``0``; y < n; y++) ``//update Y labels` `      ``if` `(T[y])` `        ``ly[y] += delta;` `    ``for` `(y = ``0``; y < n; y++) ``//update slack array` `      ``if` `(!T[y])` `        ``slack[y] -= delta;` `  ``}`   `  ``public` `static` `void` `add_to_tree(``int` `x, ``int` `prev_iousx) ` `    ``//x - current vertex,prev_iousx - vertex from X before x in the alternating path,` `    ``//so we add edges (prev_iousx, xy[x]), (xy[x], x)` `  ``{` `    ``S[x] = ``true``; ``//add x to S` `    ``prev_ious[x] = prev_iousx; ``//we need this when augmenting` `    ``for` `(``int` `y = ``0``; y < n; y++) ``//update slacks, because we add new vertex to S` `      ``if` `(lx[x] + ly[y] - cost[x][y] < slack[y])` `      ``{` `        ``slack[y] = lx[x] + ly[y] - cost[x][y];` `        ``slackx[y] = x;` `      ``}` `  ``}`       `  ``public` `static` `void` `augment() ``//main function of the algorithm` `  ``{` `    ``if` `(max_match == n) ``return``; ``//check whether matching is already perfect` `    ``int` `x, y; ``//just counters and root vertex` `    ``int` `q[] = ``new` `int``[n], wr = ``0``, rd = ``0``; ``//q - queue for bfs, wr,rd - write and read` `    ``//pos in queue` `    ``Arrays.fill(S, ``false``); ``//init set S` `    ``Arrays.fill(T, ``false``); ``//init set T` `    ``Arrays.fill(prev_ious, -``1``); ``//init set prev_ious - for the alternating tree` `    ``int` `root = -``1``;`   `    ``for` `(x = ``0``; x < n; x++) ``//finding root of the tree` `    ``{` `      ``if` `(xy[x] == -``1``)` `      ``{` `        ``q[wr++] = root = x;` `        ``prev_ious[x] = -``2``;` `        ``S[x] = ``true``;` `        ``break``;` `      ``}` `    ``}` `    ``if` `(root == -``1``) {` `      ``// All vertices are already matched` `      ``return``;` `    ``}` `    ``for` `(y = ``0``; y < n; y++) ``//initializing slack array` `    ``{` `      ``slack[y] = lx[root] + ly[y] - cost[root][y];` `      ``slackx[y] = root;` `    ``}`   `    ``//second part of augment() function` `    ``while` `(``true``) ``//main cycle` `    ``{` `      ``while` `(rd < wr) ``//building tree with bfs cycle` `      ``{` `        ``x = q[rd++]; ``//current vertex from X part` `        ``for` `(y = ``0``; y < n; y++) ``//iterate through all edges in equality graph` `          ``if` `(cost[x][y] == lx[x] + ly[y] && !T[y])` `          ``{` `            ``if` `(yx[y] == -``1``) ``break``; ``//an exposed vertex in Y found, so` `            ``//augmenting path exists!` `            ``T[y] = ``true``; ``//else just add y to T,` `            ``q[wr++] = yx[y]; ``//add vertex yx[y], which is matched` `            ``//with y, to the queue` `            ``add_to_tree(yx[y], x); ``//add edges (x,y) and (y,yx[y]) to the tree` `          ``}` `        ``if` `(y < n)` `          ``break``; ``//augmenting path found!` `      ``}` `      ``if` `(y < n)` `        ``break``; ``//augmenting path found!`   `      ``update_labels(); ``//augmenting path not found, so improve labeling`   `      ``wr = rd = ``0``; ` `      ``for` `(y = ``0``; y < n; y++) ` `        ``//in this cycle we add edges that were added to the equality graph as a` `        ``//result of improving the labeling, we add edge (slackx[y], y) to the tree if` `        ``//and only if !T[y] && slack[y] == 0, also with this edge we add another one` `        ``//(y, yx[y]) or augment the matching, if y was exposed` `        ``if` `(!T[y] && slack[y] == ``0``)` `        ``{` `          ``if` `(yx[y] == -``1``) ``//exposed vertex in Y found - augmenting path exists!` `          ``{` `            ``x = slackx[y];` `            ``break``;` `          ``}` `          ``else` `          ``{` `            ``T[y] = ``true``; ``//else just add y to T,` `            ``if` `(!S[yx[y]]) ` `            ``{` `              ``q[wr++] = yx[y]; ``//add vertex yx[y], which is matched with` `              ``//y, to the queue` `              ``add_to_tree(yx[y], slackx[y]); ``//and add edges (x,y) and (y,` `              ``//yx[y]) to the tree` `            ``}` `          ``}` `        ``}` `      ``if` `(y < n) ``break``; ``//augmenting path found!` `    ``}`   `    ``if` `(y < n) ``//we found augmenting path!` `    ``{` `      ``max_match++; ``//increment matching` `      ``//in this cycle we inverse edges along augmenting path` `      ``for` `(``int` `cx = x, cy = y, ty; cx != -``2``; cx = prev_ious[cx], cy = ty)` `      ``{` `        ``ty = xy[cx];` `        ``yx[cy] = cx;` `        ``xy[cx] = cy;` `      ``}` `      ``augment(); ``//recall function, go to step 1 of the algorithm` `    ``}` `  ``}``//end of augment() function`   `  ``public` `static` `int` `hungarian()` `  ``{` `    ``int` `ret = ``0``; ``//weight of the optimal matching` `    ``max_match = ``0``; ``//number of vertices in current matching` `    ``xy = ``new` `int``[n];` `    ``yx = ``new` `int``[n];` `    ``Arrays.fill(xy, -``1``);` `    ``Arrays.fill(yx, -``1``);` `    ``init_labels(); ``//step 0` `    ``augment(); ``//steps 1-3`   `    ``for` `(``int` `x = ``0``; x < n; x++) ``//forming answer there` `      ``ret += cost[x][xy[x]];`   `    ``return` `ret;` `  ``}`   `  ``public` `static` `int` `assignmentProblem(``int` `Arr[], ``int` `N) {`   `    ``n = N;` `    ``cost = ``new` `int``[n][n];` `    ``lx = ``new` `int``[n];` `    ``ly = ``new` `int``[n];` `    ``S = ``new` `boolean``[n];` `    ``T = ``new` `boolean``[n];` `    ``slack = ``new` `int``[n];` `    ``slackx = ``new` `int``[n];` `    ``prev_ious = ``new` `int``[n];`   `    ``for``(``int` `i=``0``; i

## Python3

 `# python implementation of the above approach. ` `class` `Solution:`   `    ``def` `__init__(``self``):` `        `  `        ``# cost matrix` `        ``self``.cost ``=` `[[]]``*``31` `        ``for` `i ``in` `range``(``31``):` `            ``self``.cost[i] ``=` `[``0``]``*``31`   `        ``self``.n ``=` `0``; ``# n workers and n jobs` `        ``self``.max_match ``=` `0``; ``# n workers and n jobs` `        ``self``.lx ``=` `[``0``]``*``31` `# labels of X and Y parts` `        ``self``.ly ``=` `[``0``]``*``31` `# labels of X and Y parts` `        ``self``.xy ``=` `[``0``]``*``31` `# xy[x] - vertex that is matched with x,` `        ``self``.yx ``=` `[``0``]``*``31` `# yx[y] - vertex that is matched with y` `        ``self``.S ``=` `[``False``]``*``31` `# sets S and T in algorithm` `        ``self``.T ``=` `[``False``]``*``31` `# sets S and T in algorithm` `        ``self``.slack ``=` `[``0``]``*``31` `# as in the algorithm description` `        ``self``.slackx ``=` `[``0``]``*``31` `# slackx[y] such a vertex, that` `        ``self``.prev_ious ``=` `[``0``]``*``31` `# array for memorizing alternating p` `        `  `  `  `    ``def` `init_labels(``self``):` `        ``for` `i ``in` `range``(``len``(``self``.lx)):` `            ``self``.lx[i] ``=` `0` `        ``for` `i ``in` `range``(``len``(``self``.ly)):` `            ``self``.ly[i] ``=` `0`         `        `  `        ``for` `x ``in` `range``(``self``.n):` `            ``for` `y ``in` `range``(``self``.n):` `                ``self``.lx[x] ``=` `max``(``self``.lx[x], ``self``.cost[x][y])` `    `  `     `  `    ``def` `update_labels(``self``):` `        ``x ``=` `0` `        ``y ``=` `0` `        ``delta ``=` `99999999` `# init delta as infinity` `        `  `        ``for` `y ``in` `range``(``self``.n): ``# calculate delta using slack` `            ``if` `this.T[y] ``=``=` `False``:` `                ``delta ``=` `math.``min``(delta, ``self``.slack[y])` `                `  `                `  `        ``for` `x ``in` `range``(``self``.n):` `            ``if` `self``.S[x] ``=``=` `True``: ``# update X labels` `                ``self``.lx[x] ``-``=` `delta`   `        ``for` `y ``in` `range``(``self``.n):` `            ``if` `self``.T[y] ``=``=` `True``:` `                ``self``.ly[y] ``+``=` `delta ``# update Y labels` `        `  `        ``for` `y ``in` `range``(``self``.n):` `            ``if` `self``.T[y] ``=``=` `False``:` `                ``self``.slack[y] ``-``=` `delta ``# update slack array` `    `  `    `  `    ``def` `add_to_tree(``self``, x, prev_iousx):` `        `  `    ``# x - current vertex,prev_iousx - vertex from X before x in the alternating path,` `    ``# so we add edges (prev_iousx, xy[x]), (xy[x], x)` `        ``self``.S[x] ``=` `True` `# add x to S` `        ``self``.prev_ious[x] ``=` `prev_iousx ``# we need this when augmenting` `        ``for` `y ``in` `range``(``self``.n):` `            ``if` `self``.lx[x] ``+` `self``.ly[y] ``-` `self``.cost[x][y] < ``self``.slack[y]:` `                ``self``.slack[y] ``=` `self``.lx[x] ``+` `self``.ly[y] ``-` `self``.cost[x][y]` `                ``self``.slackx[y] ``=` `x` `    `  `    `  `    `  `    ``def` `augment(``self``): ``# main function of the algorithm` `        ``if` `self``.max_match ``=``=` `self``.n:` `            ``return` `# check whether matching is already perfect` `        ``x``=` `0` `        ``y ``=` `0` `        ``root ``=` `0` `# just counters and root vertex` `        ``q``=` `[``0``]``*``31` `        ``wr ``=` `0` `        ``rd ``=` `0` `# q - queue for bfs, wr,rd - write and read` `        ``# pos in queue` `        ``for` `i ``in` `range``(``len``(``self``.S)):` `            ``self``.S[i] ``=` `False` `# init set S` `        ``for` `i ``in` `range``(``len``(``self``.T)):` `            ``self``.T[i] ``=` `False` `# init set T` `        ``for` `i ``in` `range``(``len``(``self``.prev_ious)):` `            ``self``.prev_ious[i] ``=` `-``1` `# init set S` `        `  `        ``for` `x ``in` `range``(``self``.n): ``# finding root. ` `            ``if` `self``.xy[x] ``=``=` `-``1``:` `                ``q[wr] ``=` `root ``=` `x` `                ``wr ``=` `wr ``+` `1` `                ``self``.prev_ious[x] ``=` `-``2` `                ``self``.S[x] ``=` `True` `                ``break`   `        ``for` `y ``in` `range``(``self``.n): ``#initializing slack array` `            ``self``.slack[y] ``=` `self``.lx[root] ``+` `self``.ly[y] ``-` `self``.cost[root][y]` `            ``self``.slackx[y] ``=` `root` `        `  `        ``# second part of augment() function` `        ``while` `(``True``): ``# main cycle` `        `  `            ``while` `(rd < wr): ``# building tree with bfs cycle` `                ``x ``=` `q[rd]` `                ``rd ``=` `rd ``+` `1` `# current vertex from X part` `                ``for` `y ``in` `range``(``self``.n): ``# iterate through all edges in equality graph` `                    ``if` `self``.cost[x][y] ``=``=` `self``.lx[x] ``+` `self``.ly[y] ``and` `self``.T[y] ``=``=` `False``:` `                        ``if` `self``.yx[y] ``=``=` `-``1``:` `                            ``break` `# an exposed vertex in Y found, so` `                                                ``# augmenting path exists!` `                        ``this.T[y] ``=` `True` `# else just add y to T,` `                        ``q[wr] ``=` `self``.yx[y] ``# add vertex yx[y], which is matched` `                        ``wr ``=` `wr ``+` `1` `                        ``# with y, to the queue` `                        ``self``.add_to_tree(``self``.yx[y], x) ``# add edges (x,y) and (y,yx[y]) to the tree` `        `  `                ``if` `y < ``self``.n:` `                    ``break` `# augmenting path found!` `            ``if` `y < ``self``.n:` `                ``break` `# augmenting path found!` `            `  `            ``self``.update_labels() ``#augmenting path not found, so improve labeling` `            `  `            ``wr ``=` `0` `            ``rd ``=` `0` `        `  `            ``for` `y ``in` `range``(``self``.n):` `                ``if` `self``.T[y] ``=``=` `False` `and` `self``.slack[y] ``=``=` `0``:` `                    ``if` `self``.yx[y] ``=``=` `-``1``: ``# exposed vertex in Y found - augmenting path exists!` `                        ``x ``=` `self``.slackx[y]` `                        ``break` `                    ``else``:` `                        ``self``.T[y] ``=` `True` `# else just add y to T,` `                        ``if` `self``.S[``self``.yx[y]] ``=``=` `False``:` `                    `  `                            ``q[wr] ``=` `self``.yx[y] ``# add vertex yx[y], which is matched with` `                            ``wr ``=` `wr ``+` `1` `                            ``# y, to the queue` `                            ``self``.add_to_tree(``self``.yx[y], ``self``.slackx[y]); ``# and add edges (x,y) and (y,` `                            ``# //yx[y]) to the tree` `            ``if` `y < ``self``.n:` `                ``break` `# augmenting path found!` `        `  `        ``if` `y < ``self``.n: ``# we found augmenting path!` `            ``self``.max_match ``=` `self``.max_match ``+` `1` `# increment matching` `            ``# in this cycle we inverse edges along augmenting path` `            ``cx ``=` `x` `            ``cy ``=` `y` `            ``ty ``=` `0` `            ``while``(cx !``=` `-``2``):` `                `  `                ``ty  ``=` `self``.xy[cx]` `                ``self``.yx[cy] ``=` `cx` `                ``self``.xy[cx] ``=` `cy` `            `  `                ``cx ``=` `self``.prev_ious[cx]` `                ``cy ``=` `ty` `            ``self``.augment() ``#recall function, go to step 1 of the algorithm` `        ``# end of augment() function` `     `  `    ``def` `hungarian(``self``):` `        `  `        ``ret ``=` `0` `# weight of the optimal matching` `        ``self``.max_match ``=` `0``; ``# number of vertices in current matching` `        ``for` `i ``in` `range``(``len``(``self``.xy)):` `            ``self``.xy[i] ``=` `-``1` `        ``for` `i ``in` `range``(``len``(``self``.yx)):` `            ``self``.yx[i] ``=` `-``1`   `        ``self``.init_labels() ``# step 0` `        ``self``.augment() ``# steps 1-3` `        `  `        ``for` `x ``in` `range``(``self``.n):` `            ``ret ``+``=` `self``.cost[x][``self``.xy[x]]` `        `  `        ``return` `ret` `    `  `    ``def` `assignmentProblem(``self``, Arr, N):` `        `  `        ``self``.n ``=` `N` `        ``for` `i ``in` `range``(``self``.n):` `            ``for` `j ``in` `range``(``self``.n):` `                ``self``.cost[i][j] ``=` `-``1``*``Arr[i``*``self``.n ``+` `j]` `                `  `        ``ans ``=` `-``1` `*` `self``.hungarian()` `        `  `        ``return` `ans ``-` `2000`     `n``=``3` `Arr ``=` `[``1500``,``4000``,``4500``,``2000``,``6000``,``3500``,``2000``,``4000``,``2500``]   ` `ob ``=` `Solution()` `print``(ob.assignmentProblem( Arr,n))`   `# The code is contributed by Nidhi goel. `

## C#

 `using` `System;` `using` `System.Collections.Generic;` `using` `System.Collections;` `using` `System.Linq;` `// C# code implementation `   `class` `Solution {`   `  ``public` `int` `n;` `  ``public` `int``[][] cost = ``new` `int``[31][]; ``//cost matrix` `  ``public` `int` `max_match; ``//n workers and n jobs` `  ``public` `int``[] lx = ``new` `int``[31];` `  ``public` `int``[] ly = ``new` `int``[31]; ``//labels of X and Y parts` `  ``public` `int``[] xy = ``new` `int``[31]; ``//xy[x] - vertex that is matched with x,` `  ``public` `int``[] yx = ``new` `int``[31]; ``//yx[y] - vertex that is matched with y` `  ``public` `int``[] S = ``new` `int``[31];` `  ``public` `int``[] T = ``new` `int``[31]; ``//sets S and T in algorithm` `  ``public` `int``[] slack = ``new` `int``[31]; ``//as in the algorithm description` `  ``public` `int``[] slackx = ``new` `int``[31]; ``//slackx[y] such a vertex, that` `  ``public` `int``[] prev_ious = ``new` `int``[31]; ``//array for memorizing alternating p`   `  ``public` `void` `init_labels()` `  ``{` `    ``for``(``int` `i = 0; i < lx.Length; i++) lx[i] = 0;` `    ``for``(``int` `i = 0; i < ly.Length; i++) ly[i] = 0;` `    ``for` `(``int` `x = 0; x < n; x++)` `      ``for` `(``int` `y = 0; y < n; y++)` `        ``lx[x] = Math.Max(lx[x], cost[x][y]);` `  ``}`     `  ``public` `void` `update_labels()` `  ``{` `    ``int` `x, y;` `    ``int` `delta = 99999999; ``//init delta as infinity` `    ``for` `(y = 0; y < n; y++) ``//calculate delta using slack` `      ``if` `(T[y] == 0)` `        ``delta = Math.Min(delta, slack[y]);` `    ``for` `(x = 0; x < n; x++) ``//update X labels` `      ``if` `(S[x] == 1)` `        ``lx[x] -= delta;` `    ``for` `(y = 0; y < n; y++) ``//update Y labels` `      ``if` `(T[y] == 1)` `        ``ly[y] += delta;` `    ``for` `(y = 0; y < n; y++) ``//update slack array` `      ``if` `(T[y]==0)` `        ``slack[y] -= delta;` `  ``}`   `  ``public` `void` `add_to_tree(``int` `x, ``int` `prev_iousx) ` `    ``//x - current vertex,prev_iousx - vertex from X before x in the alternating path,` `    ``//so we add edges (prev_iousx, xy[x]), (xy[x], x)` `  ``{` `    ``S[x] = 1; ``//add x to S` `    ``prev_ious[x] = prev_iousx; ``//we need this when augmenting` `    ``for` `(``int` `y = 0; y < n; y++) ``//update slacks, because we add new vertex to S` `      ``if` `(lx[x] + ly[y] - cost[x][y] < slack[y])` `      ``{` `        ``slack[y] = lx[x] + ly[y] - cost[x][y];` `        ``slackx[y] = x;` `      ``}` `  ``}`       `  ``public` `void` `augment() ``//main function of the algorithm` `  ``{` `    ``if` `(max_match == n) ``return``; ``//check whether matching is already perfect` `    ``int` `x, y; ``//just counters and root vertex` `    ``int``[] q = ``new` `int``[n];` `    ``int` `wr = 0, rd = 0; ``//q - queue for bfs, wr,rd - write and read` `    ``//pos in queue` `    ``for``(``int` `i = 0; i < S.Length; i++) S[i] = 0;` `    ``for``(``int` `i = 0; i < T.Length; i++) T[i] = 0;` `    ``for``(``int` `i = 0; i < prev_ious.Length; i++) prev_ious[i] = -1;` `    ``int` `root = -1;`   `    ``for` `(x = 0; x < n; x++) ``//finding root of the tree` `    ``{` `      ``if` `(xy[x] == -1)` `      ``{` `        ``q[wr] = root = x;` `        ``wr = wr + 1;` `        ``prev_ious[x] = -2;` `        ``S[x] = 1;` `        ``break``;` `      ``}` `    ``}` `    ``if` `(root == -1) {` `      ``// All vertices are already matched` `      ``return``;` `    ``}` `    ``for` `(y = 0; y < n; y++) ``//initializing slack array` `    ``{` `      ``slack[y] = lx[root] + ly[y] - cost[root][y];` `      ``slackx[y] = root;` `    ``}`   `    ``//second part of augment() function` `    ``while` `(``true``) ``//main cycle` `    ``{` `      ``while` `(rd < wr) ``//building tree with bfs cycle` `      ``{` `        ``x = q[rd++]; ``//current vertex from X part` `        ``for` `(y = 0; y < n; y++) ``//iterate through all edges in equality graph` `          ``if` `(cost[x][y] == lx[x] + ly[y] && T[y]==0)` `          ``{` `            ``if` `(yx[y] == -1) ``break``; ``//an exposed vertex in Y found, so` `            ``//augmenting path exists!` `            ``T[y] = 1; ``//else just add y to T,` `            ``q[wr] = yx[y]; ``//add vertex yx[y], which is matched` `              ``wr =wr +1;` `            ``//with y, to the queue` `            ``add_to_tree(yx[y], x); ``//add edges (x,y) and (y,yx[y]) to the tree` `          ``}` `        ``if` `(y < n)` `          ``break``; ``//augmenting path found!` `      ``}` `      ``if` `(y < n)` `        ``break``; ``//augmenting path found!`   `      ``update_labels(); ``//augmenting path not found, so improve labeling`   `      ``wr = rd = 0; ` `      ``for` `(y = 0; y < n; y++) ` `        ``//in this cycle we add edges that were added to the equality graph as a` `        ``//result of improving the labeling, we add edge (slackx[y], y) to the tree if` `        ``//and only if !T[y] && slack[y] == 0, also with this edge we add another one` `        ``//(y, yx[y]) or augment the matching, if y was exposed` `        ``if` `(T[y]==0 && slack[y] == 0)` `        ``{` `          ``if` `(yx[y] == -1) ``//exposed vertex in Y found - augmenting path exists!` `          ``{` `            ``x = slackx[y];` `            ``break``;` `          ``}` `          ``else` `          ``{` `            ``T[y] = 1; ``//else just add y to T,` `            ``if` `(S[yx[y]] ==0) ` `            ``{` `              ``q[wr++] = yx[y]; ``//add vertex yx[y], which is matched with` `              ``//y, to the queue` `              ``add_to_tree(yx[y], slackx[y]); ``//and add edges (x,y) and (y,` `              ``//yx[y]) to the tree` `            ``}` `          ``}` `        ``}` `      ``if` `(y < n) ``break``; ``//augmenting path found!` `    ``}`   `    ``if` `(y < n) ``//we found augmenting path!` `    ``{` `      ``max_match++; ``//increment matching` `      ``//in this cycle we inverse edges along augmenting path` `      ``for` `(``int` `cx = x, cy = y, ty; cx != -2; cx = prev_ious[cx], cy = ty)` `      ``{` `        ``ty = xy[cx];` `        ``yx[cy] = cx;` `        ``xy[cx] = cy;` `      ``}` `      ``augment(); ``//recall function, go to step 1 of the algorithm` `    ``}` `  ``}``//end of augment() function`   `  ``public` `int` `hungarian()` `  ``{` `    ``int` `ret = 0; ``//weight of the optimal matching` `    ``max_match = 0; ``//number of vertices in current matching` `    ``xy = ``new` `int``[n];` `    ``yx = ``new` `int``[n];` `    ``for``(``int` `i = 0; i < xy.Length; i++) xy[i] = -1;` `    ``for``(``int` `i = 0; i < yx.Length; i++) yx[i] = -1;` `    ``init_labels(); ``//step 0` `    ``augment(); ``//steps 1-3`   `    ``for` `(``int` `x = 0; x < n; x++) ``//forming answer there` `      ``ret += cost[x][xy[x]];`   `    ``return` `ret;` `  ``}`   `  ``public` `int` `assignmentProblem(``int``[] Arr, ``int` `N) {` `    `  `    ``// initialising cost array. ` `    ``for``(``int` `i = 0; i < 31; i++){` `        ``cost[i] = ``new` `int``[31];` `    ``}` `      `  `    ``n = N;` `    ``for``(``int` `i=0; i

## Javascript

 `// Javascript implementation of the above approach. ` `class Solution {`   `    ``constructor(){` `        `  `        ``// cost matrix` `        ``this``.cost = ``new` `Array(31);` `        ``for``(let i = 0; i < 31; i++){` `            ``this``.cost[i] = ``new` `Array(31).fill(0);` `        ``}` `        `  `        ``this``.n = 0; ``//n workers and n jobs` `        ``this``.max_match = 0; ``//n workers and n jobs` `        ``this``.lx = ``new` `Array(31).fill(0); ``//labels of X and Y parts` `        ``this``.ly = ``new` `Array(31).fill(0); ``//labels of X and Y parts` `        ``this``.xy = ``new` `Array(31).fill(0); ``//xy[x] - vertex that is matched with x,` `        ``this``.yx = ``new` `Array(31).fill(0); ``//yx[y] - vertex that is matched with y` `        ``this``.S = ``new` `Array(31).fill(``false``); ``//sets S and T in algorithm` `        ``this``.T = ``new` `Array(31).fill(``false``); ``//sets S and T in algorithm` `        ``this``.slack = ``new` `Array(31).fill(0); ``//as in the algorithm description` `        ``this``.slackx = ``new` `Array(31).fill(0); ``//slackx[y] such a vertex, that` `        ``this``.prev_ious = ``new` `Array(31).fill(0); ``//array for memorizing alternating p` `        `  `    ``}` `  `  `    ``init_labels()` `    ``{` `        ``for``(let i = 0; i < ``this``.lx.length; i++) ``this``.lx[i] = 0;` `        ``for``(let i = 0; i < ``this``.ly.length; i++) ``this``.ly[i] = 0;` `        `  `        ``for` `(let x = 0; x < ``this``.n; x++)` `            ``for` `(let y = 0; y < ``this``.n; y++)` `                ``this``.lx[x] = Math.max(``this``.lx[x], ``this``.cost[x][y]);` `    ``}` `    `  `     `  `    ``update_labels()` `    ``{` `        ``let x = 0;` `        ``let y = 0;` `        ``let delta = 99999999; ``//init delta as infinity` `        `  `        ``for` `(y = 0; y < ``this``.n; y++) ``//calculate delta using slack` `            ``if` `(!``this``.T[y])` `                ``delta = Math.min(delta, ``this``.slack[y]);` `        ``for` `(x = 0; x < ``this``.n; x++) ``//update X labels` `            ``if` `(``this``.S[x])` `                ``this``.lx[x] -= delta;` `        ``for` `(y = 0; y < ``this``.n; y++) ``//update Y labels` `            ``if` `(``this``.T[y])` `                ``this``.ly[y] += delta;` `        ``for` `(y = 0; y < ``this``.n; y++) ``//update slack array` `            ``if` `(!``this``.T[y])` `                ``this``.slack[y] -= delta;` `    ``}` `    `  `    `  `    ``add_to_tree(x, prev_iousx) ` `    ``//x - current vertex,prev_iousx - vertex from X before x in the alternating path,` `    ``//so we add edges (prev_iousx, xy[x]), (xy[x], x)` `    ``{` `        ``this``.S[x] = ``true``; ``//add x to S` `        ``this``.prev_ious[x] = prev_iousx; ``//we need this when augmenting` `        ``for` `(let y = 0; y < ``this``.n; y++) ``//update slacks, because we add new vertex to S` `            ``if` `(``this``.lx[x] + ``this``.ly[y] - ``this``.cost[x][y] < ``this``.slack[y])` `            ``{` `                ``this``.slack[y] = ``this``.lx[x] + ``this``.ly[y] - ``this``.cost[x][y];` `                ``this``.slackx[y] = x;` `            ``}` `    ``}` `    `  `    `  `    `  `    ``augment() ``//main function of the algorithm` `    ``{` `        ``if` `(``this``.max_match == ``this``.n) ``return``; ``//check whether matching is already perfect` `        ``let x= 0;` `        ``let y = 0;` `        ``let root = 0; ``//just counters and root vertex` `        ``let q= ``new` `Array(31);` `        ``let wr = 0;` `        ``let rd = 0; ``//q - queue for bfs, wr,rd - write and read` `        ``//pos in queue` `        ``for``(let i = 0; i < ``this``.S.length; i++) ``this``.S[i] = ``false``; ``//init set S` `        ``for``(let i = 0; i < ``this``.T.length; i++) ``this``.T[i] = ``false``; ``//init set T` `        ``for``(let i = 0; i < ``this``.prev_ious.length; i++) ``this``.prev_ious[i] = -1; ``//init set prev_ious - for the alternating tree` `        `  `        `  `        ``for` `(x = 0; x < ``this``.n; x++) ``//finding root of the tree` `        ``{` `            ``if` `(``this``.xy[x] == -1)` `            ``{` `                ``q[wr++] = root = x;` `                ``this``.prev_ious[x] = -2;` `                ``this``.S[x] = ``true``;` `                ``break``;` `            ``}` `        ``}` `        `  `        ``for` `(y = 0; y < ``this``.n; y++) ``//initializing slack array` `        ``{` `            ``this``.slack[y] = ``this``.lx[root] + ``this``.ly[y] - ``this``.cost[root][y];` `            ``this``.slackx[y] = root;` `        ``}` `        `  `        ``//second part of augment() function` `        ``while` `(``true``) ``//main cycle` `        ``{` `            ``while` `(rd < wr) ``//building tree with bfs cycle` `            ``{` `                ``x = q[rd++]; ``//current vertex from X part` `                ``for` `(y = 0; y < ``this``.n; y++) ``//iterate through all edges in equality graph` `                    ``if` `(``this``.cost[x][y] == ``this``.lx[x] + ``this``.ly[y] && !``this``.T[y])` `                    ``{` `                        ``if` `(``this``.yx[y] == -1) ``break``; ``//an exposed vertex in Y found, so` `                                                ``//augmenting path exists!` `                            ``this``.T[y] = ``true``; ``//else just add y to T,` `                        ``q[wr++] = ``this``.yx[y]; ``//add vertex yx[y], which is matched` `                        ``//with y, to the queue` `                        ``this``.add_to_tree(``this``.yx[y], x); ``//add edges (x,y) and (y,yx[y]) to the tree` `                    ``}` `                ``if` `(y < ``this``.n)` `                    ``break``; ``//augmenting path found!` `            ``}` `            ``if` `(y < ``this``.n)` `                ``break``; ``//augmenting path found!` `            `  `            ``this``.update_labels(); ``//augmenting path not found, so improve labeling` `            `  `            ``wr = rd = 0; ` `            ``for` `(y = 0; y < ``this``.n; y++) ` `            ``// in this cycle we add edges that were added to the equality graph as a` `            ``// result of improving the labeling, we add edge (slackx[y], y) to the tree if` `            ``// and only if !T[y] && slack[y] == 0, also with this edge we add another one` `            ``// (y, yx[y]) or augment the matching, if y was exposed` `            ``if` `(!``this``.T[y] && ``this``.slack[y] == 0)` `            ``{` `                ``if` `(``this``.yx[y] == -1) ``//exposed vertex in Y found - augmenting path exists!` `                ``{` `                    ``x = ``this``.slackx[y];` `                    ``break``;` `                ``}` `                ``else` `                ``{` `                    ``this``.T[y] = ``true``; ``//else just add y to T,` `                    ``if` `(!``this``.S[``this``.yx[y]]) ` `                    ``{` `                        ``q[wr++] = ``this``.yx[y]; ``//add vertex yx[y], which is matched with` `                        ``//y, to the queue` `                        ``this``.add_to_tree(``this``.yx[y], ``this``.slackx[y]); ``//and add edges (x,y) and (y,` `                        ``//yx[y]) to the tree` `                    ``}` `                ``}` `            ``}` `            ``if` `(y < ``this``.n) ``break``; ``//augmenting path found!` `        ``}` `        `  `        ``if` `(y < ``this``.n) ``//we found augmenting path!` `        ``{` `            ``this``.max_match++; ``//increment matching` `            ``// in this cycle we inverse edges along augmenting path` `            ``for` `(let cx = x, cy = y, ty; cx != -2; cx = ``this``.prev_ious[cx], cy = ty)` `            ``{` `                ``ty = ``this``.xy[cx];` `                ``this``.yx[cy] = cx;` `                ``this``.xy[cx] = cy;` `            ``}` `            ``this``.augment(); ``//recall function, go to step 1 of the algorithm` `        ``}` `    ``}``// end of augment() function` `     `  `    ``hungarian()` `    ``{` `        ``let ret = 0; ``//weight of the optimal matching` `        ``this``.max_match = 0; ``//number of vertices in current matching` `        ``for``(let i= 0; i < ``this``.xy.length; i++) ``this``.xy[i] = -1;` `        ``for``(let i = 0; i < ``this``.yx.length; i++) ``this``.yx[i] = -1;` `        ``this``.init_labels(); ``//step 0` `        ``this``.augment(); ``//steps 1-3` `        `  `        ``for` `(let x = 0; x < ``this``.n; x++) ``//forming answer there` `            ``ret += ``this``.cost[x][``this``.xy[x]];` `        `  `        ``return` `ret;` `    ``}` `    `  `    ``assignmentProblem(Arr, N) {` `        `  `        ``this``.n = N;` `        ``for``(let i=0; i<``this``.n; i++)` `            ``for``(let j=0; j<``this``.n; j++)` `                ``this``.cost[i][j] = -1*Arr[i*``this``.n+j];` `                `  `        ``let ans = -1 * ``this``.hungarian();` `        `  `        ``return` `ans;` `    ``}` `};`     `let n=3;` `let Arr = [1500,4000,4500,2000,6000,3500,2000,4000,2500];   ``/*1500  4000  4500` `                                                               ``2000  6000  3500` `                                                               ``2000  4000  2500*/` `let ob = ``new` `Solution();` `console.log(ob.assignmentProblem(Arr,n));`   `// The code is contributed by Arushi Jindal. `

Output

`8500`

Time complexity : O(n^3), where n is the number of workers and jobs. This is because the algorithm implements the Hungarian algorithm, which is known to have a time complexity of O(n^3).

Space complexity :  O(n^2), where n is the number of workers and jobs. This is because the algorithm uses a 2D cost matrix of size n x n to store the costs of assigning each worker to a job, and additional arrays of size n to store the labels, matches, and auxiliary information needed for the algorithm.

In the next post, we will be discussing implementation of the above algorithm. The implementation requires more steps as we need to find minimum number of lines to cover all 0’s using a program. References: http://www.math.harvard.edu/archive/20_spring_05/handouts/assignment_overheads.pdf https://www.youtube.com/watch?v=dQDZNHwuuOY Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!

Previous
Next
Similar Reads
Complete Tutorials