Greedy algorithm minimum search in C++? - 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;

Related

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);

Minimum cabs required (Algorithm)

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);
}
}

C++ matrix - Get number of columns where the lowest value is in the same row as the highest value in the columns after it

I'm writing a program in C++ where the inputs are N (the number of villages/rows), M (the number of days/columns) and an H[N][M]
matrix where I individually input the temperatures (min -50, max 50).
The output should be the total number of days when the village with the lowest
temperature has the highest forecast temperature, and after that the number (column) of these days in ascending order.
So if I input something like this:
3 5
10 15 12 10 10
11 11 11 11 20
12 16 16 16 20
The output should be:
2 2 3
Or input:
3 3
1 2 3
1 2 3
1 2 3
Output:
2 1 2
My approach was to first store the minimum temperatures and maximum forecast temperatures of each day into two separate arrays and
then writing a for loop where I check each village day by day if they contain both the minimum value on the given day and maximum forecast temperatures from that day on.
I have the following code:
#include <iostream>
const int maxarr = 1000;
int H[maxarr][maxarr];
using namespace std;
void read(int N, int M, int t[maxarr][maxarr]);
void count(int N, int M, int t[maxarr][maxarr]);
int main()
{
int N;
int M;
cout<<"Number of villages? ";
cin>>N;
cout<<"Number of days? ";
cin>>M;
read(N,M,H);
count(N,M,H);
return 0;
}
void read(int N, int M, int t[maxarr][maxarr])
{
for(int i = 0; i < N ; i++)
{
for(int j = 0; j < M ; j++)
{
cin>>t[i][j];
}
}
}
void count(int N, int M, int t[maxarr][maxarr])
{
int mintemparr[maxarr];
int maxtemparr[maxarr];
int mintemp;
int maxtemp;
int days[maxarr];
int cnt = 0;
for(int j = 0; j<M; j++)
{
mintemp = 51;
for(int i = 0; i<N; i++)
{
if(t[i][j]<mintemp)
{
mintemp = t[i][j];
}
mintemparr[j] = mintemp;
}
}
for(int i = 0; i < M-1; i++)
{
maxtemp = -51;
for(int j = 0; j < N; j++)
{
for(int k = i+1; k < M; k++)
{
if(t[j][k]>maxtemp)
{
maxtemp = t[j][k];
}
}
maxtemparr[i] = maxtemp;
}
}
for(int i = 0; i < M-1; i++)
{
for(int j = 0; j < N; j++)
{
for(int k = i+1; k < M; k++)
{
if(t[j][i] == mintemparr[i])
{
if(t[j][k] == maxtemparr[i])
{
days[cnt] = i+1;
cnt++;
//tried an i++ here, didn't work as intended
}
}
else
{
j++;
}
}
}
}
cout<<cnt<<" ";
for(int i = 0; i < cnt; i++)
{
cout<<days[i]<<" ";
}
}
There are some instances where it works perfectly, for example with the first input it's output is as it should be. But with the
second input I get
6 1 1 1 2 2 2
and a longer (1000x1000) input, which I obviously can't copy here also gives wrong results.
How could I make this code work as intended?
The reason why you're getting 6 1 1 1 2 2 2 for the second example is that you're not stopping to check whether a particular day fulfils the condition once you have found that it does. Thus you find that on day 1 the condition is fulfilled for village 1, village 2 and village 3 (the first three 1s in the result), and then the same happens for day 2.
From the comment
tried an i++ here, didn't work as intended
I guess you already identified that problem and the i++ was intended to prevent rechecking the same day again. However, as you noticed, that alone doesn't work - the reason here is that when skipping ahead to the next day you need to ensure that for that day checking the condition again starts with village 1 and the search for the highest temperature needs to begin from the start as well.
To do so, just add
++i; // carry on with the next day
j = 0; // start with the first village in the next iteration
k = i; // search for the highest temperature beginning from day i + 1
// note that at the end of the loop body `k` will be incremented
// so we need to use `k = i` instead of `k = i + 1` as in the loop-initializer here.
after cnt++ in place of the comment I quoted above.
With this change one gets the output you described in the question for both cases, as you can see here.
Given the input you uploaded to zippyshare I believe that the output for the second example should indeed be 3 1 2 3 instead of 2 1 2. Luckily the code is easy to change to accomodate that: Just replace all k = i + 1s by k = i and change the newly added k = i to k = i - 1 so that searching for the highest forecasts includes the present day.

Why can't I assign 1 element to 2> size dynamic tab?

Simplified version of my code looks like:
int * tab = nullptr;
int index = 0;
int size = 1; // Program works unless this is init'd to something higher!
int a = 0;
while (true)
{
int input;
std::cin >> input;
if (input == 0) break;
index++;
if (index >= size) {
size = size * 2;
int * newt = new int[size];
for (int i = 0; i < a; ++i)
newt[i] = tab[i];
delete[] tab;
tab = newt;
}
tab[a] = input;
a++;
}
Whenever I try to change 'size' integer to be bigger than 1, the program crushes. Visual Studio shouts about memory accessibility problem, but still I can't figure what's exactly wrong.
I don't have to change it, but I've struggled with this code for more than hour untill I accidently changed variable to be 1 and then it worked. I'm just curious why.
If size is bigger than one, then index >= size won't be true on the first iteration, none of the code that results in tab pointing to something is executed, so the tab[a] access is broken.
Your algorithm is rather hard to follow so I'm not proposing a concrete resolution, except to suggest redesigning it.
In addition to Lightness Races in Orbit:
Here, my approach for a revised version:
#include <iomanip>
#include <iostream>
#include <sstream>
int main()
{
int *tab = nullptr;
int len = 0, size = 0;
std::stringstream in;
in << "1 2 3 4 5 6 7 8 9 10 0";
while (true)
{
int input;
//std::cin >> input;
in >> input;
if (input == 0) break;
if (len >= size) {
size = std::max(2 * size, 1);
int * newt = new int[size];
for (int i = 0; i < len; ++i) newt[i] = tab[i];
delete[] tab;
tab = newt;
}
tab[len++] = input;
}
for (int i = 0; i < len; ++i) std::cout << ' ' << tab[i];
std::cout << '\n';
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 10
Live Demo on coliru
I must admit that I still didn't get why the original version should be broken.
There is my try on coliru which seems to run fine (although I know – running fine doesn't mean there is no U.B.). Got it.

Finding Longest Increasing Sub Sequence in a round table of numbers

I was recently working on the following problem.
http://www.codechef.com/problems/D2
The Chef is planning a buffet for the DirectiPlex inauguration party, and everyone is invited. On their way in, each guest picks up a sheet of paper containing a random number (this number may be repeated). The guests then sit down on a round table with their friends.
The Chef now decides that he would like to play a game. He asks you to pick a random person from your table and have them read their number out loud. Then, moving clockwise around the table, each person will read out their number. The goal is to find that set of numbers which forms an increasing subsequence. All people owning these numbers will be eligible for a lucky draw! One of the software developers is very excited about this prospect, and wants to maximize the number of people who are eligible for the lucky draw. So, he decides to write a program that decides who should read their number first so as to maximize the number of people that are eligible for the lucky draw. Can you beat him to it?
Input
The first line contains t, the number of test cases (about 15). Then t test cases follow. Each test case consists of two lines:
The first line contains a number N, the number of guests invited to the party.
The second line contains N numbers a1, a2, ..., an separated by spaces, which are the numbers written on the sheets of paper in clockwise order.
Output
For each test case, print a line containing a single number which is the maximum number of guests that can be eligible for participating the the lucky draw.
Constraints
1 ≤ N ≤ 10000
You may assume that each number number on the sheet of paper; ai is randomly generated, i.e. can be with equal probability any number from an interval [0,U], where U is some upper bound (1 ≤ U ≤ 106).
Example
Input:
3
2
0 0
3
3 2 1
6
4 8 6 1 5 2
Output:
1
2
4
On checking the solutions I found this code:
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#define LIMIT 37
using namespace std;
struct node {
int val;
int index;
};
int N;
int binary(int number, vector<int>& ans) {
int start = 0;
int n = ans.size();
int end = n - 1;
int mid;
if (start == end)
return 0;
while (start != end) {
mid = (start + end) / 2;
if (ans[mid] == number)
break;
if (ans[mid] > number)
end = mid;
else
start = mid + 1;
}
mid = (start + end) / 2;
return mid;
}
void display(vector<int>& list) {
cout << endl;
for (int i = 0; i < list.size(); i++)
cout << list[i] << " ";
cout << endl;
}
int maxsubsequence(vector<int>& list) {
vector<int> ans;
int N = list.size();
ans.push_back(list[0]);
int i;
// display(list);
for (i = 1; i < N; i++) {
int index = binary(list[i], ans);
/*if(index+1<ans.size())
continue;*/
if (list[i] < ans[index])
ans[index] = list[i];
if (list[i] > ans[index])
ans.push_back(list[i]);
// display(ans);
}
return ans.size();
}
int compute(int index, int* g) {
vector<int> list;
list.push_back(g[index]);
int itr = (index + 1) % N;
while (itr != index) {
list.push_back(g[itr]);
itr = (itr + 1) % N;
}
return maxsubsequence(list);
}
int solve(int* g, vector<node> list) {
int i;
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
return ret;
}
bool cmp(const node& o1, const node& o2)
{ return (o1.val < o2.val); }
int g[10001];
int main() {
int t;
cin >> t;
while (t--) {
cin >> N;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
cin >> g[i];
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
Can someone explain this to me. I am well aware of calculating LIS in nlog(n).
What I am not able to understand is this part:
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
and the reason behind sorting
sort(list.begin(),list.end(),cmp);
This algorithm is simply guessing at the starting point and computing the LIS for each of these guesses.
The first value in a LIS is likely to be a small number, so this algorithm simply tries the LIMIT smallest values as potential starting points.
The sort function is used to identify the smallest values.
The for loop is used to check each starting point in turn.
WARNING
Note that this algorithm may fail for certain inputs. For example, consider the sequence
0,1,2,..,49,9900,9901,...,99999,50,51,52,...,9899
The algorithm will try just the first 37 starting points and miss the best starting point at 50.
You can test this by changing the code to:
int main() {
int t;
t=1;
while (t--) {
N=10000;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
if (i<50)
g[i]=i;
else if (i<150)
g[i]=9999-150+i;
else
g[i]=i-100;
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
This will generate different answers depending on whether LIMIT is 37 or 370.
In practice, for randomly generated sequences it will have a good chance of working (although I don't know how to compute the probability exactly).