Sorting Activty for Number of Solutions for Systems
Greedy is an algorithmic paradigm that builds up a solution piece by piece, always choosing the next piece that offers the most obvious and immediate benefit. Greedy algorithms are used for optimization problems. An optimization problem can be solved using Greedy if the problem has the following property: At every step, we can make a choice that looks best at the moment, and we get the optimal solution of the complete problem.
If a Greedy Algorithm can solve a problem, then it generally becomes the best method to solve that problem as the Greedy algorithms are in general more efficient than other techniques like Dynamic Programming. But Greedy algorithms cannot always be applied. For example, the Fractional Knapsack problem can be solved using Greedy, but 0-1 Knapsack cannot be solved using Greedy.
Following are some standard algorithms that are Greedy algorithms.
1) Kruskal's Minimum Spanning Tree (MST) : In Kruskal's algorithm, we create a MST by picking edges one by one. The Greedy Choice is to pick the smallest weight edge that doesn't cause a cycle in the MST constructed so far.
2) Prim's Minimum Spanning Tree : In Prim's algorithm also, we create a MST by picking edges one by one. We maintain two sets: a set of the vertices already included in MST and the set of the vertices not yet included. The Greedy Choice is to pick the smallest weight edge that connects the two sets.
3) Dijkstra's Shortest Path : Dijkstra's algorithm is very similar to Prim's algorithm. The shortest-path tree is built up, edge by edge. We maintain two sets: a set of the vertices already included in the tree and the set of the vertices not yet included. The Greedy Choice is to pick the edge that connects the two sets and is on the smallest weight path from source to the set that contains not yet included vertices.
4) Huffman Coding : Huffman Coding is a loss-less compression technique. It assigns variable-length bit codes to different characters. The Greedy Choice is to assign the least bit length code to the most frequent character.
The greedy algorithms are sometimes also used to get an approximation for Hard optimization problems. For example, Traveling Salesman Problem is an NP-Hard problem. A Greedy choice for this problem is to pick the nearest unvisited city from the current city at every step. These solutions don't always produce the best optimal solution but can be used to get an approximately optimal solution.
Let us consider the Activity Selection problem as our first example of Greedy algorithms. Following is the problem statement.
You are given n activities with their start and finish times. Select the maximum number of activities that can be performed by a single person, assuming that a person can only work on a single activity at a time.
Example:
Become a success story instead of just reading about them. Prepare for coding interviews at Amazon and other top product-based companies with our Amazon Test Series. Includes topic-wise practice questions on all important DSA topics along with 10 practice contests of 2 hours each. Designed by industry experts that will surely help you practice and sharpen your programming skills. Wait no more, start your preparation today!
Example 1 : Consider the following 3 activities sorted by by finish time. start[] = {10, 12, 20}; finish[] = {20, 25, 30}; A person can perform at most two activities. The maximum set of activities that can be executed is {0, 2} [ These are indexes in start[] and finish[] ] Example 2 : Consider the following 6 activities sorted by by finish time. start[] = {1, 3, 0, 5, 8, 5}; finish[] = {2, 4, 6, 7, 9, 9}; A person can perform at most four activities. The maximum set of activities that can be executed is {0, 1, 3, 4} [ These are indexes in start[] and finish[] ]
The greedy choice is to always pick the next activity whose finish time is least among the remaining activities and the start time is more than or equal to the finish time of the previously selected activity. We can sort the activities according to their finishing time so that we always consider the next activity as minimum finishing time activity.
1) Sort the activities according to their finishing time
2) Select the first activity from the sorted array and print it.
3) Do the following for the remaining activities in the sorted array.
…….a) If the start time of this activity is greater than or equal to the finish time of the previously selected activity then select this activity and print it.
In the following C implementation, it is assumed that the activities are already sorted according to their finish time.
C++
#include <bits/stdc++.h>
using
namespace
std;
void
printMaxActivities(
int
s[],
int
f[],
int
n)
{
int
i, j;
cout <<
"Following activities are selected "
<< endl;
i = 0;
cout <<
" "
<< i;
for
(j = 1; j < n; j++)
{
if
(s[j] >= f[i])
{
cout <<
" "
<< j;
i = j;
}
}
}
int
main()
{
int
s[] = {1, 3, 0, 5, 8, 5};
int
f[] = {2, 4, 6, 7, 9, 9};
int
n =
sizeof
(s)/
sizeof
(s[0]);
printMaxActivities(s, f, n);
return
0;
}
C
#include<stdio.h>
void
printMaxActivities(
int
s[],
int
f[],
int
n)
{
int
i, j;
printf
(
"Following activities are selected n"
);
i = 0;
printf
(
"%d "
, i);
for
(j = 1; j < n; j++)
{
if
(s[j] >= f[i])
{
printf
(
"%d "
, j);
i = j;
}
}
}
int
main()
{
int
s[] = {1, 3, 0, 5, 8, 5};
int
f[] = {2, 4, 6, 7, 9, 9};
int
n =
sizeof
(s)/
sizeof
(s[0]);
printMaxActivities(s, f, n);
return
0;
}
Java
import
java.util.*;
import
java.lang.*;
import
java.io.*;
class
ActivitySelection
{
public
static
void
printMaxActivities(
int
s[],
int
f[],
int
n)
{
int
i, j;
System.out.print(
"Following activities are selected : n"
);
i =
0
;
System.out.print(i+
" "
);
for
(j =
1
; j < n; j++)
{
if
(s[j] >= f[i])
{
System.out.print(j+
" "
);
i = j;
}
}
}
public
static
void
main(String[] args)
{
int
s[] = {
1
,
3
,
0
,
5
,
8
,
5
};
int
f[] = {
2
,
4
,
6
,
7
,
9
,
9
};
int
n = s.length;
printMaxActivities(s, f, n);
}
}
C#
using
System;
class
GFG
{
public
static
void
printMaxActivities(
int
[] s,
int
[] f,
int
n)
{
int
i, j;
Console.Write(
"Following activities are selected : "
);
i = 0;
Console.Write(i +
" "
);
for
(j = 1; j < n; j++)
{
if
(s[j] >= f[i])
{
Console.Write(j +
" "
);
i = j;
}
}
}
public
static
void
Main()
{
int
[] s = {1, 3, 0, 5, 8, 5};
int
[] f = {2, 4, 6, 7, 9, 9};
int
n = s.Length;
printMaxActivities(s, f, n);
}
}
Python
def
printMaxActivities(s , f ):
n
=
len
(f)
print
"The following activities are selected"
i
=
0
print
i,
for
j
in
xrange
(n):
if
s[j] >
=
f[i]:
print
j,
i
=
j
s
=
[
1
,
3
,
0
,
5
,
8
,
5
]
f
=
[
2
,
4
,
6
,
7
,
9
,
9
]
printMaxActivities(s , f)
PHP
<?php
function
printMaxActivities(
$s
,
$f
,
$n
)
{
echo
"Following activities are selected "
.
"\n"
;
$i
= 0;
echo
$i
.
" "
;
for
(
$j
= 1;
$j
<
$n
;
$j
++)
{
if
(
$s
[
$j
] >=
$f
[
$i
])
{
echo
$j
.
" "
;
$i
=
$j
;
}
}
}
$s
=
array
(1, 3, 0, 5, 8, 5);
$f
=
array
(2, 4, 6, 7, 9, 9);
$n
= sizeof(
$s
);
printMaxActivities(
$s
,
$f
,
$n
);
?>
Javascript
<script>
function
printMaxActivities(s,f,n)
{
let i, j;
document.write(
"Following activities are selected : n"
);
i = 0;
document.write(i+
" "
);
for
(j = 1; j < n; j++)
{
if
(s[j] >= f[i])
{
document.write(j+
" "
);
i = j;
}
}
}
let s = [1, 3, 0, 5, 8, 5]
let f = [2, 4, 6, 7, 9, 9]
let n = s.length;
printMaxActivities(s, f, n);
</script>
Output
Following activities are selected n0 1 3 4
How does Greedy Choice work for Activities sorted according to finish time?
Let the given set of activities be S = {1, 2, 3, …n} and activities are sorted by finish time. The greedy choice is to always pick activity 1. How come activity 1 always provides one of the optimal solutions. We can prove it by showing that if there is another solution B with the first activity other than 1, then there is also a solution A of the same size with activity 1 as the first activity. Let the first activity selected by B be k, then there always exist A = {B – {k}} U {1}.
(Note that the activities in B are independent and k has the smallest finishing time among all. Since k is not 1, finish(k) >= finish(1)).
How to implement when given activities are not sorted?
We create a structure/class for activities. We sort all activities by finish time (Refer sort in C++ STL). Once we have activities sorted, we apply the same algorithm.
Below image is an illustration of the above approach:
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using
namespace
std;
struct
Activitiy
{
int
start, finish;
};
bool
activityCompare(Activitiy s1, Activitiy s2)
{
return
(s1.finish < s2.finish);
}
void
printMaxActivities(Activitiy arr[],
int
n)
{
sort(arr, arr+n, activityCompare);
cout <<
"Following activities are selected n"
;
int
i = 0;
cout <<
"("
<< arr[i].start <<
", "
<< arr[i].finish <<
"), "
;
for
(
int
j = 1; j < n; j++)
{
if
(arr[j].start >= arr[i].finish)
{
cout <<
"("
<< arr[j].start <<
", "
<< arr[j].finish <<
"), "
;
i = j;
}
}
}
int
main()
{
Activitiy arr[] = {{5, 9}, {1, 2}, {3, 4}, {0, 6},
{5, 7}, {8, 9}};
int
n =
sizeof
(arr)/
sizeof
(arr[0]);
printMaxActivities(arr, n);
return
0;
}
Java
import
java.io.*;
import
java.util.*;
class
Activity
{
int
start, finish;
public
Activity(
int
start,
int
finish)
{
this
.start = start;
this
.finish = finish;
}
}
class
Compare
{
static
void
compare(Activity arr[],
int
n)
{
Arrays.sort(arr,
new
Comparator<Activity>()
{
@Override
public
int
compare(Activity s1, Activity s2)
{
return
s1.finish - s2.finish;
}
});
}
}
class
GFG {
static
void
printMaxActivities(Activity arr[],
int
n)
{
Compare obj =
new
Compare();
obj.compare(arr, n);
System.out.println(
"Following activities are selected :"
);
int
i =
0
;
System.out.print(
"("
+ arr[i].start +
", "
+ arr[i].finish +
"), "
);
for
(
int
j =
1
; j < n; j++)
{
if
(arr[j].start >= arr[i].finish)
{
System.out.print(
"("
+ arr[j].start +
", "
+ arr[j].finish +
"), "
);
i = j;
}
}
}
public
static
void
main(String[] args)
{
int
n =
6
;
Activity arr[] =
new
Activity[n];
arr[
0
] =
new
Activity(
5
,
9
);
arr[
1
] =
new
Activity(
1
,
2
);
arr[
2
] =
new
Activity(
3
,
4
);
arr[
3
] =
new
Activity(
0
,
6
);
arr[
4
] =
new
Activity(
5
,
7
);
arr[
5
] =
new
Activity(
8
,
9
);
printMaxActivities(arr, n);
}
}
Python3
def
MaxActivities(arr, n):
selected
=
[]
Activity.sort(key
=
lambda
x : x[
1
])
i
=
0
selected.append(arr[i])
for
j
in
range
(
1
, n):
if
arr[j][
0
] >
=
arr[i][
1
]:
selected.append(arr[j])
i
=
j
return
selected
Activity
=
[[
5
,
9
], [
1
,
2
], [
3
,
4
], [
0
,
6
],[
5
,
7
], [
8
,
9
]]
n
=
len
(Activity)
selected
=
MaxActivities(Activity, n)
print
(
"Following activities are selected :"
)
print
(selected)
Javascript
<script>
function
MaxActivities(arr, n){
let selected = [];
Activity = Activity.sort(
function
(a,b) {
return
a[1] - b[1];
});
let i = 0
selected.push(arr[i]);
for
(let j=1;j<n;j++){
if
( arr[j][0] >= arr[i][1]){
selected.push(arr[j]);
i = j;
}
}
return
selected;
}
Activity = [[5, 9], [1, 2], [3, 4], [0, 6],[5, 7], [8, 9]];
n = Activity.length;
selected = MaxActivities(Activity, n);
document.write(
"Following activities are selected : <br>"
)
console.log(selected)
for
(let i = 0;i<selected.length;i++)
document.write(
"("
+selected[i]+
"), "
)
</script>
Output:
Following activities are selected (1, 2), (3, 4), (5, 7), (8, 9),
Time Complexity: It takes O(n log n) time if input activities may not be sorted. It takes O(n) time when it is given that input activities are always sorted.
Using STL we can solve it as follows:
CPP
#include <bits/stdc++.h>
using
namespace
std;
void
SelectActivities(vector<
int
>s,vector<
int
>f){
vector<pair<
int
,
int
>>ans;
priority_queue<pair<
int
,
int
>,vector<pair<
int
,
int
>>,greater<pair<
int
,
int
>>>p;
for
(
int
i=0;i<s.size();i++){
p.push(make_pair(f[i],s[i]));
}
auto
it = p.top();
int
start = it.second;
int
end = it.first;
p.pop();
ans.push_back(make_pair(start,end));
while
(!p.empty()){
auto
itr = p.top();
p.pop();
if
(itr.second >= end){
start = itr.second;
end = itr.first;
ans.push_back(make_pair(start,end));
}
}
cout <<
"Following Activities should be selected. "
<< endl << endl;
for
(
auto
itr=ans.begin();itr!=ans.end();itr++){
cout <<
"Activity started at: "
<< (*itr).first <<
" and ends at "
<< (*itr).second << endl;
}
}
int
main()
{
vector<
int
>s = {1, 3, 0, 5, 8, 5};
vector<
int
>f = {2, 4, 6, 7, 9, 9};
SelectActivities(s,f);
return
0;
}
Java
import
java.io.*;
import
java.lang.*;
import
java.util.*;
class
GFG {
static
class
Pair {
int
first;
int
second;
Pair(
int
first,
int
second)
{
this
.first = first;
this
.second = second;
}
}
static
void
SelectActivities(
int
s[],
int
f[])
{
ArrayList<Pair> ans =
new
ArrayList<>();
PriorityQueue<Pair> p =
new
PriorityQueue<>(
(p1, p2) -> p1.first - p2.first);
for
(
int
i =
0
; i < s.length; i++) {
p.add(
new
Pair(f[i], s[i]));
}
Pair it = p.poll();
int
start = it.second;
int
end = it.first;
ans.add(
new
Pair(start, end));
while
(!p.isEmpty()) {
Pair itr = p.poll();
if
(itr.second >= end) {
start = itr.second;
end = itr.first;
ans.add(
new
Pair(start, end));
}
}
System.out.println(
"Following Activities should be selected. \n"
);
for
(Pair itr : ans) {
System.out.println(
"Activity started at: "
+ itr.first
+
" and ends at "
+ itr.second);
}
}
public
static
void
main(String[] args)
{
int
s[] = {
1
,
3
,
0
,
5
,
8
,
5
};
int
f[] = {
2
,
4
,
6
,
7
,
9
,
9
};
SelectActivities(s, f);
}
}
Javascript
<script>
class Pair
{
constructor(first,second)
{
this
.first = first;
this
.second = second;
}
}
function
SelectActivities(s,f)
{
let ans = [];
let p = [];
for
(let i = 0; i < s.length; i++) {
p.push(
new
Pair(f[i], s[i]));
}
p.sort(
function
(a,b){
return
a.first-b.first;});
let it = p.shift();
let start = it.second;
let end = it.first;
ans.push(
new
Pair(start, end));
while
(p.length!=0) {
let itr = p.shift();
if
(itr.second >= end) {
start = itr.second;
end = itr.first;
ans.push(
new
Pair(start, end));
}
}
document.write(
"Following Activities should be selected. <br>"
);
for
(let itr of ans.values()) {
document.write(
"Activity started at: "
+ itr.first
+
" and ends at "
+ itr.second+
"<br>"
);
}
}
let s=[1, 3, 0, 5, 8, 5 ];
let f=[2, 4, 6, 7, 9, 9 ];
SelectActivities(s, f);
</script>
Output
Following Activities should be selected. Activity started at: 1 and ends at 2 Activity started at: 3 and ends at 4 Activity started at: 5 and ends at 7 Activity started at: 8 and ends at 9
Sorting Activty for Number of Solutions for Systems
Source: https://www.geeksforgeeks.org/activity-selection-problem-greedy-algo-1/