0% found this document useful (0 votes)
31 views12 pages

CO34563 Assignment 4

The document discusses solving an assignment problem using the Hungarian algorithm. It provides pseudocode for the Hungarian algorithm and analyzes its time and space complexity as O(n^3) and O(n^2) respectively. It then provides an implementation of the Hungarian algorithm in C++ to solve the assignment problem and returns the minimum cost.

Uploaded by

kapib57390
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views12 pages

CO34563 Assignment 4

The document discusses solving an assignment problem using the Hungarian algorithm. It provides pseudocode for the Hungarian algorithm and analyzes its time and space complexity as O(n^3) and O(n^2) respectively. It then provides an implementation of the Hungarian algorithm in C++ to solve the assignment problem and returns the minimum cost.

Uploaded by

kapib57390
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

0801CS211072 Raj Gupta

1. For the following problems, write pseudocode solutions and state the worse case running time
(in terms of Θ or O where appropriate). Also give the correctness of the yours algorithms. You
will be graded on the efficiency of your solutions. After that implement the algorithms in any
programming language and verified the complexity of the yours algorithm.

Problem 1: Assume that we have N workers and N jobs that should be done. For each pair
(worker, job) we know salary that should be paid to worker for him to perform the job.
Our goal is to complete all jobs minimizing total inputs, while assigning each worker to
exactly one job and vice versa. Converting this problem to a formal mathematical
definition we can form the following equations:
C is a cost matrix of NxN where cij is cost of worker i to perform job j.
X is resulting binary matrix, where xij = 1 if and only if ith worker is assigned to jth job.
] one worker to one job assignment.
] one job to one worker assignment.
is a total cost function and it should be minimize.
We can also rephrase this problem in terms of graph theory. Let’s look at the job and
workers as if they were a bipartite graph, where each edge between the ith worker and jth
job has weight of cij. Write a program to find minimum-weight matching in the graph (the
matching will consists of N edges, because our bipartite graph is complete).
Solutions:
Approach 1: Hungarian Algorithm (Munkres Algorithm):
Pseudocode:
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.
Time complexity : O(n^3),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.
#include<bits/stdc++.h>
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

1
0801CS211072 Raj Gupta

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

2
0801CS211072 Raj Gupta

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;

3
0801CS211072 Raj Gupta

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

4
0801CS211072 Raj Gupta

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<n; i++)
for(int j=0; j<n; j++)
cost[i][j] = -1*Arr[i*n+j];

int ans = -1 * hungarian();

return ans;
}
};

int main()
{
int n=3;
int Arr[3*3]={1500,4000,4500,2000,6000,3500,2000,4000,2500}; /*1500 4000 4500

2000 6000 3500

2000 4000 2500*/


Solution ob;
cout<<ob.assignmentProblem(Arr,n)<<endl;
}
Approach 2 : Branch-and-Bound Algorithm:
Pseudocode:
function branch_and_bound(cost_matrix, current_assignment, current_cost, lower_bound):
if all(worker is not None for worker in current_assignment):
if current_cost < minimum_cost:
minimum_cost = current_cost
minimum_assignment = current_assignment.copy()
return

for job in range(len(cost_matrix)):


if current_assignment[job] is None:
current_assignment[job] = worker_index

new_lower_bound = calculate_lower_bound(cost_matrix, current_assignment)


if new_lower_bound < minimum_cost:
branch_and_bound(cost_matrix, current_assignment.copy(), current_cost +
cost_matrix[worker_index][job], new_lower_bound)

5
0801CS211072 Raj Gupta

current_assignment[job] = None

return None

Problem 2: Suppose you are given an array A[1 .. n] of integers, each of which may be positive,
negative, or zero. A contiguous subarray A[i .. j] is called a positive interval if the sum of its
entries is greater than zero. Describe and analyze an algorithm to compute the minimum
number of positive intervals that cover every positive entry in A. For example, given the
following array as input, your algorithm should output the number 3.

Approach
One approach to solving this problem is to use a greedy algorithm. The algorithm
scans the array from left to right, maintaining a running sum. Whenever the running
sum becomes positive, it starts a new positive interval. Whenever the running sum
becomes negative or zero, it ends the current positive interval. By doing this, we
can count the number of positive intervals needed to cover every positive entry in
the array.
Pseudocode:
function min_positive_intervals(A):
n = length of array A
intervals = 0
running_sum = 0

for i from 1 to n:
running_sum += A[i]
if running_sum > 0:
intervals++
running_sum = 0

return intervals

Time Complexity:

This algorithm has a time complexity of O(n) since it scans the array once.

Problem 3: Consider the following bridge crossing problem where n people with speeds s1; : : : ;
sn wish to cross the bridge as quickly as possible. The rules remain:

6
0801CS211072 Raj Gupta

(a) It is nighttime and you only have one ash-light.


(b) A maximum of two people can cross at any one time
(c) Any party who crosses, either 1 or 2 people must have the ash-light with them.
(d) The ash-light must be walked back and forth, it cannot be thrown, etc.
(e) A pair must walk together at the rate of the slower person’s pace.
Give an efficient algorithm to find the fastest way to get a group of people across the
bridge. You must have a proof of correctness for your method.
Greedy Algorithm for Bridge Crossing Problem
function bridge_crossing_speedy(people_speeds):
Sort people_speeds in non-decreasing order // O(n log n)

time_taken = 0
crossing_sequence = []

while people_speeds is not empty:


if length of people_speeds is 1:
// Only one person left, they cross alone
time_taken += people_speeds[0]
crossing_sequence.append([people_speeds[0]])
break

if length of people_speeds is 2:
// Two people left, they cross together
time_taken += max(people_speeds[0], people_speeds[1])
crossing_sequence.append([people_speeds[0], people_speeds[1]])
break

// Otherwise, select two fastest people to cross together


fastest_pair = [people_speeds[0], people_speeds[1]]
time_taken += max(people_speeds[0], people_speeds[1])
crossing_sequence.append(fastest_pair)

// Remove the crossed people from the list


people_speeds = people_speeds[2:]

return time_taken, crossing_sequence

7
0801CS211072 Raj Gupta

Program:

Complexity Analysis
Sorting O(nlogn) time, (n) iterations in the worst case.
The overall time complexity O(nlogn)

To prove the correctness of this algorithm, we need to show that it always produces an optimal
solution. We can argue that selecting the fastest pairs to cross at each step minimizes the total
time taken for all crossings.
Since the two people in each crossing pair must walk together at the rate of the slower person's
pace, it's optimal to pair the fastest person with the slowest person available. This way, the faster

8
0801CS211072 Raj Gupta

person's speed is effectively "wasted" by matching them with the slower person, minimizing the
total time taken for each crossing.
Therefore, by always selecting the fastest pairs to cross, the algorithm ensures that each trip takes
the least possible time, resulting in an optimal overall solution.

Problem 7: Write a program for the following problem:


INPUT: Positive integers r1;r2;:::;rn and c1;:::;cn.
OUTPUT: An n by n matrix A with 0/1 entries such that for all i the sum of the ith row in A is
ri and the sum of the ith column in A is ci, if such a matrix exists.
Think of the problem this way. You want to put pawns on an n by n chessboard so that the
ith row has ri pawns and the ith column has ci pawns

Program:

9
0801CS211072 Raj Gupta

Analysis:
The time complexity of this approach is O(rows×cols)

Problem 10: There are N floors and N persons each one is tagged with some random unique
number between 1 to N (represents floor number). We have a lift which can
accommodate one person at a time. Every person is in some random floor. Initially lift is at
floor 1 and all floors have single person. Design an algorithm to move the persons to their
corresponding floor with minimum number of lift movements. [Restriction: Lift can have
at most one person at a time. While moving persons, at some point of time, we can keep
more than one person at one floor.
One approach to solving is a Greedy Algorithm, specifically the "Nearest Neighbor" approach. This
approach involves always moving the lift to the nearest floor where a person needs to be dropped off. Here's
the pseudocode for this approach:

10
0801CS211072 Raj Gupta

function elevatorScheduling(persons):
n = length of persons
lift_position = 1

# Sort persons by floor number


sorted_persons = sort(persons)

# Move the lift


for person_floor in sorted_persons:
if person_floor != lift_position:
move_lift_to(person_floor)
drop_off_person(person_floor)
lift_position = person_floor

Program:

11
0801CS211072 Raj Gupta

Algorithm Analysis:
The time complexity of this approach is O(N log N).

12

You might also like