Minimum cabs required (Algorithm) - c++

I am trying to solve this question:
https://www.hackerearth.com/practice/algorithms/greedy/basics-of-greedy-algorithms/practice-problems/algorithm/minimum-cabs-0798cfa5/description/
I see a solution here but I don't quite understand it.
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1500;
int A[MAX];
int main(int argc, char* argv[])
{
if(argc == 2 or argc == 3) freopen(argv[1], "r", stdin);
if(argc == 3) freopen(argv[2], "w", stdout);
ios::sync_with_stdio(false);
int n, hh1, hh2, mm1, mm2, smins, emins, ans;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> hh1 >> mm1 >> hh2 >> mm2;
smins = hh1 * 60 + mm1;
emins = hh2 * 60 + mm2;
A[smins]++;
A[emins+1]--;
}
ans = A[0];
for (int i = 1; i < MAX; i++) {
A[i] += A[i-1];
ans = max(ans, A[i]);
}
cout << ans << endl;
return 0;
}
Could someone explain the algorithm to me?

The given solution works on maximum overlapping intervals.
The author wants to count the maximum number of intervals or ranges which overlap at any given point in the time.
Assume a time scale, which represents time:
Min time: 00:00 => represents 0 on the time scale
Max time: 23:59 => represents 1439 on the time scale
So, author used a constant MAX as 1500, thus making a time scale of [0, 1500], which satisfies our requirement.
Now, for each interval/ range we got from the input, author made use of prefix sum, thus adding 1 to every time unit in the range.
For eg: Suppose my range is 00:00 to 12:36, then I will add 1 to every index of array A from 0 to 756.
The maximum prefix sum denotes the minimum number of cabs required as 1 cab can be only be allocated to 1 person at any particular instance of time.
Hope this helps. Feel free to ask any doubts. Kindly mark answer correct if satisfies your doubt.

class TestClass
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
int arr[] = new int[24*60+1];
while(t!=0)
{
int st = sc.nextInt()*60+sc.nextInt();
int et = sc.nextInt()*60+sc.nextInt();
for(int i=st;i<=et;i++)
{
arr[i]++;
}
t--;
}
int max=0;
for(int i=0;i<arr.length;i++)
{
max=Math.max(max,arr[i]);
}
System.out.println(max);
}
}

Related

Tips on Improving Efficiency of this Code (Beginner)

I am currently doing a coding exercise and am missing some cases due to the time limit being exceeded. Can I get some tips on how to improve the efficiency of my code? Also if you have any general tips for a beginner I would also appreciate that. The problem is below and thanks.
You are given all numbers between 1,2,…,n except one. Your task is to find the missing number.
Input
The first input line contains an integer n.
The second line contains n−1 numbers. Each number is distinct and between 1 and n (inclusive).
Output
Print the missing number.
Constraints
2≤n≤2⋅105
Example
Input:
5
2 3 1 5
Output:
4
Here is my code:
#include <bits/stdc++.h>
using namespace std;
int missingNumber(vector<int> available, int N) {
for (int i=1; i<=N; i++) {
bool counter = false;
for (int j=0; j<N-1; j++) {
if (i == available[j]) {
counter = true;
}
}
if (counter == false) {
return i;
}
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int N;
cin >> N;
vector<int> available(N-1);
int temp = 0;
for (int i=0; i<N-1; i++) {
cin >> temp;
available[i] = temp;
}
cout << missingNumber(available, N);
}
A very simple solution with O(N) complexity is based on the observation that if the N-1 numbers are all between 1 and N and distinct from each other, then it suffices to:
compute the sum of all these N-1 numbers, so linear complexity
subtract the sum computed at step 1 from the sum of the N numbers from 1 to N, which we know is N * (N + 1) / 2, so O(1) complexity.
here is an answer with two versions to your problem
the first version is using Arithmetic progression formula n*(a1 + an) /2
and then subtract your vector sum with the result of the formula.
double missingNumber_ver1(std::vector<int> available, int N) {
// formula for sum for Arithmetic progression
double sum = N * (available[0]+available[N-2]) /2;
double available_sym = std::accumulate(available.begin(), available.end(), 0); // this is to sum the giving numbers
double missing_num = sum-available_sym;
return missing_num;
}
the second version is to use XOR operator and when there is a xor value that is not 0 that means this is the missing number. I'm also using std::iota to build the comparison vector with range values.
double missingNumber_ver2(std::vector<int> available, int N) {
std::vector<int>tem_vec(N-1);
std::iota(tem_vec.begin(), tem_vec.end(), available[0]);
auto av_it = available.begin();
auto tem_vec_it = tem_vec.begin();
while(!(*av_it ^ *tem_vec_it))
{
av_it++;
tem_vec_it++;
}
return *tem_vec_it;
}
and here is the full code - look that I made few changes also in the main() function
#include <iostream>
#include <numeric>
#include <vector>
double missingNumber_ver1(std::vector<int> available, int N) {
// formula for sum for Arithmetic progression
double sum = N * (available[0]+available[N-2]) /2;
double available_sym = std::accumulate(available.begin(), available.end(), 0);
double missing_num = sum-available_sym;
return missing_num;
}
double missingNumber_ver2(std::vector<int> available, int N) {
std::vector<int>tem_vec(4);
std::iota(tem_vec.begin(), tem_vec.end(), available[0]);
auto av_it = available.begin();
auto tem_vec_it = tem_vec.begin();
while(!(*av_it ^ *tem_vec_it))
{
av_it++;
tem_vec_it++;
}
return *tem_vec_it;
}
int main() {
int N;
std::cin >> N;
std::vector<int> available;
int temp = 0;
for (int i=0; i<N-1; i++) {
std::cin >> temp;
available.push_back(temp);
}
std::cout << "missingNumber_ver1 " << missingNumber_ver1(available, N) << "\n";
std::cout << "missingNumber_ver2 " <<missingNumber_ver2(available, N) << "\n";
}

Unıque Random Number Check form Array c++

#include <iostream>
#include<ctime>
#include<cstdlib>
#include<string>
#include<cmath>
using namespace std;
int main()
{
bool cont = false;
string str;
int num, num2;
cin >> str >> num;
int arr[10];
int a = pow(10, num);
int b = pow(10, (num - 1));
srand(static_cast<int>(time(NULL)));
do {
num2 = rand() % (a - b) + b;
int r;
int i = 0;
int cpy = num2;
while (cpy != 0) {
r = cpy % 10;
arr[i] = r;
i++;
cpy = cpy / 10;
}
for (int m = 0; m < num; m++)
{
for (int j = 0; j < m; j++) {
if (m != j) {
if (arr[m] == arr[j]) {
break;
}
else {
cont = true;
}
}
}
}
cout << num2 << endl;
} while (!cont);
return 0;
}
I want to take a number from the user and produce such a random number.
For example, if the user entered 8, an 8-digit random number.This number must be unique, so each number must be different from each other,for example:
user enter 5
random number=11225(invalid so take new number)
random number =12345(valid so output)
To do this, I divided the number into its digits and threw it into the array and checked whether it was unique. The Program takes random numbers from the user and throws them into the array.It's all right until this part.But my function to check if this number is unique using the for loop does not work.
Because you need your digits to be unique, it's easier to guarantee the uniqueness up front and then mix it around. The problem-solving principle at play here is to start where you are the most constrained. For you, it's repeating digits, so we ensure that will never happen. It's a lot easier than verifying if we did or not.
This code example will print the unique number to the screen. If you need to actually store it in an int, then there's extra work to be done.
#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>
int main() {
std::vector<int> digits(10);
std::iota(digits.begin(), digits.end(), 0);
std::shuffle(digits.begin(), digits.end(), std::mt19937(std::random_device{}()));
int x;
std::cout << "Number: ";
std::cin >> x;
for (auto it = digits.begin(); it != digits.begin() + x; ++it) {
std::cout << *it;
}
std::cout << '\n';
}
A few sample runs:
Number: 7
6253079
Number: 3
893
Number: 6
170352
The vector digits holds the digits 0-9, each only appearing once. I then shuffle them around. And based on the number that's input by the user, I then print the first x single digits.
The one downside to this code is that it's possible for 0 to be the first digit, and that may or may not fit in with your rules. If it doesn't, you'd be restricted to a 9-digit number, and the starting value in std::iota would be 1.
First I'm going to recommend you make better choices in naming your variables. You do this:
bool cont = false;
string str;
int num, num2;
cin >> str >> num;
What are num and num2? Give them better names. Why are you cin >> str? I can't even see how you're using it later. But I presume that num is the number of digits you want.
It's also not at all clear what you're using a and b for. Now, I presume this next bit of code is an attempt to create a number. If you're going to blindly try and then when done, see if it's okay, why are you making this so complicated. Instead of this:
num2 = rand() % (a - b) + b;
int r;
int i = 0;
int cpy = num2;
while (cpy != 0) {
r = cpy % 10;
arr[i] = r;
i++;
cpy = cpy / 10;
}
You can do this:
for(int index = 0; index < numberOfDesiredDigits; ++index) {
arr[index] = rand() % 10;
}
I'm not sure why you went for so much more complicated.
I think this is your code where you validate:
// So you iterate the entire array
for (int m = 0; m < num; m++)
{
// And then you check all the values less than the current spot.
for (int j = 0; j < m; j++) {
// This if not needed as j is always less than m.
if (m != j) {
// This if-else is flawed
if (arr[m] == arr[j]) {
break;
}
else {
cont = true;
}
}
}
}
You're trying to make sure you have no duplicates. You're setting cont == true if the first and second digit are different, and you're breaking as soon as you find a dup. I think you need to rethink that.
bool areAllUnique = true;
for (int m = 1; allAreUnique && m < num; m++) {
for (int j = 0; allAreUnique && j < m; ++j) {
allAreUnique = arr[m] != arr[j];
}
}
As soon as we encounter a duplicate, allAreUnique becomes false and we break out of both for-loops.
Then you can check it.
Note that I also start the first loop at 1 instead of 0. There's no reason to start the outer loop at 0, because then the inner loop becomes a no-op.
A better way is to keep a set of valid digits -- initialized with 1 to 10. Then grab a random number within the size of the set and grabbing the n'th digit from the set and remove it from the set. You'll get a valid result the first time.

How to find all possible combinations of adding two variables, each attached to a multiplier, summing up to a given number (cin)?

In my situation, a lorry has a capacity of 30, while a van has a capacity of 10. I need to find the number of vans/lorries needed to transport a given amount of cargo, say 100. I need to find all possible combinations of lorries + vans that will add up to 100.
The basic math calculation would be: (30*lorrycount) + (10*vancount) = n, where n is number of cargo.
Output Example
Cargo to be transported: 100
Number of Lorry: 0 3 2 1
Number of Van: 10 1 4 7
For example, the 2nd combination is 3 lorries, 1 van. Considering that lorries have capacity = 30 and van capacity = 10, (30*3)+(10*1) = 100 = n.
For now, we only have this code, which finds literally all combinations of numbers that add up to given number n, without considering the formula given above.
#include <iostream>
#include <vector>
using namespace std;
void findCombinationsUtil(int arr[], int index,
int num, int reducedNum)
{
int lorry_capacity = 30;
int van_capacity = 10;
// Base condition
if (reducedNum < 0)
return;
// If combination is found, print it
if (reducedNum == 0)
{
for (int i = 0; i < index; i++)
cout << arr[i] << " ";
cout << endl;
return;
}
// Find the previous number stored in arr[]
// It helps in maintaining increasing order
int prev = (index == 0) ? 1 : arr[index - 1];
// note loop starts from previous number
// i.e. at array location index - 1
for (int k = prev; k <= num; k++)
{
// next element of array is k
arr[index] = k;
// call recursively with reduced number
findCombinationsUtil(arr, index + 1, num,
reducedNum - k);
}
}
void findCombinations(int n)
{
// array to store the combinations
// It can contain max n elements
std::vector<int> arr(n); // allocate n elements
//find all combinations
findCombinationsUtil(&*arr.begin(), 0, n, n);
}
int main()
{
int n;
cout << "Enter the amount of cargo you want to transport: ";
cin >> n;
cout << endl;
//const int n = 10;
findCombinations(n);
return 0;
}
Do let me know if you have any solution to this, thank you.
An iterative way of finding all possible combinations
#include <iostream>
#include <vector>
int main()
{
int cw = 100;
int lw = 30, vw = 10;
int maxl = cw/lw; // maximum no. of lorries that can be there
std::vector<std::pair<int,int>> solutions;
// for the inclusive range of 0 to maxl, find the corresponding no. of vans for each variant of no of lorries
for(int l = 0; l<= maxl; ++l){
bool is_integer = (cw - l*lw)%vw == 0; // only if this is true, then there is an integer which satisfies for given l
if(is_integer){
int v = (cw-l*lw)/vw; // no of vans
solutions.push_back(std::make_pair(l,v));
}
}
for( auto& solution : solutions){
std::cout<<solution.first<<" lorries and "<< solution.second<<" vans" <<std::endl;
}
return 0;
}
We will create a recursive function that walks a global capacities array left to right and tries to load cargo into the various vehicle types. We keep track of how much we still have to load and pass that on to any recursive call. If we reach the end of the array, we produce a solution only if the remaining cargo is zero.
std::vector<int> capacities = { 30, 10 };
using Solution = std::vector<int>;
using Solutions = std::vector<Solution>;
void tryLoad(int remaining_cargo, int vehicle_index, Solution so_far, std::back_insert_iterator<Solutions>& solutions) {
if (vehicle_index == capacities.size()) {
if (remaining_cargo == 0) // we have a solution
*solutions++ = so_far;
return;
}
int capacity = capacities[vehicle_index];
for (int vehicles = 0; vehicles <= remaining_cargo / capacity; vehicles++) {
Solution new_solution = so_far;
new_solution.push_back(vehicles);
tryLoad(remaining_cargo - vehicles * capacity, vehicle_index + 1, new_solution, solutions);
}
}
Calling this as follows should produce the desired output in all_solutions:
Solutions all_solutions;
auto inserter = std::back_inserter(all_solutions)
tryLoad(100, 0, Solution{}, inserter);

Greedy algorithm minimum search in C++?

I have a C++ assignment which I've been working on in the last 2 weeks. My knowledge is very limited, as I just started learning C++ and algorithms in February.
The assignment is:
N number of guests were invited to a party. We know all guests arrival and leave time. We want to know which guest met the LEAST amount of other guests. Two guests meet when guest1_arrivaltime <= guest2_leavetime and guest2_arrivaltime <= guest1_leavetime. If there are multiple guests who met the same amount of other guests, only one needs to be printed out.
Use: standard input (cin, cout) and greedy algorithm.
N (number of guests) can range from 1 to 1 000 000, the arrival and leave time values can be between 1 and 100 000
Run time limitation: 0.1 second
Memory limitation: 32 MB
I have a working code which seems to be okay to me, but when I upload it to the school's server I only get 27 marks out of 100. I need 50 marks to pass.
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
struct guestData
{
int guestIndex;
int time;
guestData(int guestIndex, int time)
{
this->guestIndex = guestIndex;
this->time = time;
}
guestData()
{
guestIndex = 0;
time = 0;
}
};
int n;
guestData * arrive;
guestData * leave;
set<int> guestsIn;
set<int> * metSet;
int minGuests;
int minIndex = 1;
bool operator<(const guestData & l, const guestData & r)
{
return l.time < r.time;
}
void read(int n)
{
arrive = new guestData[n];
leave = new guestData[n];
metSet = new set<int>[n];
minGuests = n;
for (int i = 0; i < n; ++i){
int arriveTime;
int leaveTime;
cin >> arriveTime >> leaveTime;
arrive[i] = guestData(i, arriveTime);
leave[i] = guestData(i, leaveTime);
}
}
void process()
{
sort(arrive, arrive+n);
sort(leave, leave+n);
int i = 0, j = 0;
while (i < n && j < n)
{
if (arrive[i].time <= leave[j].time)
{
int currentTime = arrive[i].time;
int in = arrive[i].guestIndex;
for (auto it = guestsIn.begin(); it != guestsIn.end(); ++it)
{
metSet[in].insert(*it);
metSet[*it].insert(in);
}
guestsIn.insert(in);
i++;
}
else
{
int currentTime = leave[j].time;
int out = leave[j].guestIndex;
guestsIn.erase(out);
j++;
}
}
}
void findMin(){
for (int i = 0; i < n; ++i)
{
if (metSet[i].size() < minGuests)
{
minGuests = metSet[i].size();
minIndex = i+1;
}
}
}
int main()
{
cin >> n;
read(n);
process();
findMin();
cout << minIndex << " " << minGuests;
return 0;
}
The problem: it works great on the example input, which is:
8
1 3
4 8
9 12
2 5
3 9
7 10
2 3
1 3
where 8 is the n (number of guests) and then 8 x the arrival(left row) and leave time(right row) for the guests.
The output for this example input is: 3 2 which is correct, because the 3rd guests met the least amount of other guests (2)
However, I get this error on my school's website when I upload my code: ERROR CODE 11 ILLEGAL MEMORY REFERENCE
You should free the memory at the end of the program. The grading system probably detects you are not doing that.
delete[] arrive;
delete[] leave;
delete[] metSet;

Multiplication with functions in C++

I am new to functions and i am really trying to understand how they work, my teacher gave us a problem where by we were to pass a number to a function between the range of 1-12 and the function was then meant to do the times tales of that number so I asked the user to enter a number and if the number is less then 1 and greater then 12 exit, else pass the number to the function and then I used a for loop to do the multiplication for me (as far as I am aware) but nothing seems to happen? Νo doubt I am doing something really stupid, any help is much appreciated.
#include <iostream>
using namespace std;
int TimesTables (int num);
int main(int argc, const char * argv[]) {
int number;
cout << "enter a number to multiply by, with a range of 1-12: ";
cin >> number;
if (number < 1 && number > 12)
return EXIT_FAILURE;
else {
int tables = TimesTables(number);
cout << tables;
}
return 0;
}
int TimesTables (int num) {
for ( int i = 0; num <=12; i ++)
num = num * i;
return num;
}
Running i from 0 is going to set num to 0, and therefore any multiplication after that.
Your loop is also rather dubious. Why are you checking num <= 12 rather than i <= 12?
Shouldn't your loop take the form
for ( int i = 1; i <=12; i ++){
// Print num * i
cout << num * i;
}
// There's no need to return anything back to the caller
for ( int i = 0; num <=12; i ++)
num = num * i;
Here i starts from 0, so any multiplication you do afterwards doesn't affect the result (num). Moreover, you want to go from 1 to 12, so you should start from 0 and finish at 12 - 1, or start from 1 and finish at 12.
So change this:
for ( int i = 0; num <=12; i ++)
to this:
for ( int i = 1; i <=12; i ++)
since you want to stop when i reaches 12, not num, i is the counter of the for-loop!