need help for codejam question "PARENTING PARTNERSHIP" - c++

This question was asked on 4th april in google codejam : https://codingcompetitions.withgoogle.com/codejam/round/000000000019fd27/000000000020bdf9.
The description of question is :
Cameron and Jamie's kid is almost 3 years old! However, even though the child is more independent now, scheduling kid activities and domestic necessities is still a challenge for the couple.
Cameron and Jamie have a list of N activities to take care of during the day. Each activity happens during a specified interval during the day. They need to assign each activity to one of them, so that neither of them is responsible for two activities that overlap. An activity that ends at time t is not considered to overlap with another activity that starts at time t.
For example, suppose that Jamie and Cameron need to cover 3 activities: one running from 18:00 to 20:00, another from 19:00 to 21:00 and another from 22:00 to 23:00. One possibility would be for Jamie to cover the activity running from 19:00 to 21:00, with Cameron covering the other two. Another valid schedule would be for Cameron to cover the activity from 18:00 to 20:00 and Jamie to cover the other two. Notice that the first two activities overlap in the time between 19:00 and 20:00, so it is impossible to assign both of those activities to the same partner.
Given the starting and ending times of each activity, find any schedule that does not require the same person to cover overlapping activities, or say that it is impossible.
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing a single integer N, the number of activities to assign. Then, N more lines follow. The i-th of these lines (counting starting from 1) contains two integers Si and Ei. The i-th activity starts exactly Si minutes after midnight and ends exactly Ei minutes after midnight.
Output
For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is IMPOSSIBLE if there is no valid schedule according to the above rules, or a string of exactly N characters otherwise. The i-th character in y must be C if the i-th activity is assigned to Cameron in your proposed schedule, and J if it is assigned to Jamie.
If there are multiple solutions, you may output any one of them.
Input :
4
3
360 480
420 540
600 660
3
0 1440
1 3
2 4
5
99 150
1 100
100 301
2 5
150 250
2
0 720
720 1440
Output :
Case #1: CJC
Case #2: IMPOSSIBLE
Case #3: JCCJJ
Case #4: CC
My approach :
sort the task values on basis of starting or ending time and check whether it can be assigned to C or J. If all the task can be assigned then all good otherwise impossible.
I tried sorting on basis of both start time and end time but for both the cases got WA.
if someone can point out what i'm missing in implementation that qoulfd be very helpful.
My code:
#include<bits/stdc++.h>
using namespace std;
typedef struct task
{
int start_time;
int finish_time;
task()
{
this->start_time=0;
this->finish_time=0;
}
task(int start_time, int finish_time)
{
this->start_time=start_time;
this->finish_time=finish_time;
}
bool operator<(const task t)
{
return this->start_time<t.start_time;
}
}task;
int main()
{
int t;
cin>>t;
int a=1;
while(t--)
{
int n,st,ft;
cin>>n;
char res[1005];
int index = 0;
vector<task> task_list;
for(int i=0;i<n;i++)
{
cin>>st>>ft;
task t1(st,ft);
task_list.push_back(t1);
}
sort(task_list.begin(),task_list.end());
task j_task, c_task;
for(int i=0;i<n;i++)
{
if(task_list[i].start_time>=j_task.finish_time)
{
j_task = task_list[i];
res[index++] = 'J';
}
else if(task_list[i].start_time>=c_task.finish_time)
{
c_task = task_list[i];
res[index++] = 'C';
}
else
{
index = 0;
break;
}
}
if(index!=0)
{
res[index] = '\0';
cout<<"Case #"<<a++<<": "<<res<<endl;
}
else
{
cout<<"Case #"<<a++<<": "<<"IMPOSSIBLE"<<endl;
}
}
return 0;
}

You are asked to assign 'C' or 'J' to the original order of the tasks given in the input. So before sorting, you should save the index of the tasks and once sorted, assign 'C' or 'J' to those saved indices.

Related

Assign the work for 2 people so that the time is minimum

Question:
There are N works that needs to be assigned for 2 people. Person A can finish work i in a[i] time, person B can finish work i in b[i] time.
Each work can only be assigned to 1 person. After the works are assigned, each person will do their works seperately.
The overall time will be the larger of the total time taken by the 2 people.
Find a way to assign the work so that the Overall Time is minimum.
Example:
N = 6
a[] = 10 100 30 50 50 80
b[] = 100 30 40 40 60 90
Answer: 130
Explaination:
Person A do work 1, 3, 6 -> total time: 120
Person B do work 2, 4, 5 -> total time: 130
Overall time: 130
Constrants:
N <= 100
a[i], b[i] <= 30.000
My take
I tried solving it with dynamic-programming, more specifically: DP[i][p][c]
With i is the number of works done so far, p is total time of person A so far, c is total time of person B so far. For each i, we can try to give the work to either person A or B, then save the best answer in DP[i][p][c] so we dont have to recalculate it.
But p and c can get up to 3.000.000, so I tried to shrink it to DP[i][max(p,c)]
The code below gives the right answer for the example case, and some other case I generated:
int n, firstCost[105], secondCost[105];
int dp[105][300005];
int solve(int i, int p, int c){
if(i > n) return max(p, c);
int &res = dp[i][max(p, c)];
if(res != -1) return res;
res = INT_MAX;
int tmp1 = solve(i+1, p + firstCost[i], c);
int tmp2 = solve(i+1, p, c + secondCost[i]);
res = min(tmp1, tmp2);
return res;
}
int main(){
// input...
cout << solve(1, 0, 0);
}
But when I submited it, it gives the wrong anwer to this case:
20
4034 18449 10427 4752 8197 7698 17402 16164 12306 5249 19076 18560 16584 18969 3548 11260 6752 18052 14684 18113
19685 10028 938 10379 11583 10383 7175 4557 850 5704 14156 18587 2869 16300 15393 14874 18859 9232 6057 3562
My output was 77759 but the answer is suppose to be 80477.
I don't know what I did wrong, is there anyway to imrpove my solution?
P/S:
Here's the original problem, the page is in Vietnamese, you can create an account and submit there
The trick that you're missing is the idea of an optimal fringe.
You are trying to shrink it to max(p,c), but it may well be that you need to send the first half the jobs to person A, and that initially looks like a terrible set of choices. You are right that you could get the right answer with DP[i][p][c], but that quickly gets to be too much data.
But suppose that p0 <= p1 and c0 <= c1. Then there is absolutely no way that looking at a path through (p1, c1) can ever lead to a better answer than (p0, c0). And therefore we can drop (p1, c1) immediately.
I won't give you code, but I'll show you a bit of how this starts with your example.
4034 18449 10427 4752 8197 7698 17402 16164 12306 5249 19076 18560 16584 18969 3548 11260 6752 18052 14684 18113
19685 10028 938 10379 11583 10383 7175 4557 850 5704 14156 18587 2869 16300 15393 14874 18859 9232 6057 3562
At first we start off with DP = [[0,0]].
After we assign the first element, you get [[0,19685], [4034,0]].
After we assign the second we get, [[0,29713], [4034,10028], [18449,19685], [22483,0]]. We can drop [18449,19685] because it isn't as good as [4034,10028], so we get to [[0,29713], [4034,10028], [22483,0]].
The third element gives [[0,30651], [4034,10966], [10427,29713], [14461,10028], [22483,938], [32910,0]] and then we can drop [10427,29713] as being worse than [4034,10966]. And now we are at [[0,30651], [4034,10966], [14461,10028], [22483,938], [32910,0]].
And so on.
As an additional optimization I'd first sort the indexes by c[i]/p[i] and produce a greedy solution where we assign all of the beginning indexes to A and all of the end to B. From the existence of that greedy solution, we never need to look at any solution with p or c worse than that known solution. After we get half-way through the jobs, this should become a useful filter.

Knapsack problem with multiple availabe packages using dynamic programming

Hello and thanks for helping!
So we've got a list of fireworks containing 1) Number in stock 2) Number of fireworks in this package 3) Diameter which equals the noise and
4) The price.
This is the list:
25 17 10 21
10 15 10 18
5 16 10 19
10 15 12 20
15 9 11 12
10 7 28 23
8 7 16 11
10 6 16 10
25 10 18 25
25 12 18 27
10 5 40 35
60 40 5 27
5 25 30 90
50 1 60 8
Our task is to create a shopping list and buy fireworks so we get the highest possible noise. We've got a knapsack capacity of 1000€. We're also supposed to solve this without using tables (so with dynamic programming instead).
I only use one class called Package which contains the four constraints as shown above.
At first I thought it would make sense to try to write an algorithm for a normal knapsack, so just with the price and the diameter (=weight). I tested it with a different list and it worked perfectly fine. I just iterated through all packages and then again used a nested for loop to find the best constellation (exhaustive search). My next idea was to merge the number of fireworks per package with the diameter, because fireworks can only be bought in a full package.
The only thing left which I still haven't found out is what to do with the amount of packages in stock. Like, with my current algorithm it just buys all packages of a firework until the knapsack is full. But obviously that won't be correct.
void knapsack(vector<Package*> stock){
vector<int> indices, tmp_indices;
int noise,tmp_noise= 0;
int price;
for (unsigned int i = 0; i < stock.size(); i++) {
price = stock[i]->price;
noise = stock[i]->diameter*stock[i]->number_fireworks;
indices.push_back(i);
for (unsigned int j = 0; j < stock.size(); j++) {
if (i != j) {
if (price+stock[j]->price<= BUDGET) {
price+=stock[j]->price;
noise+=stock[j]->diameter*stock[j]->number_fireworks;
indices.push_back(j);
}
}
}
// After second loop we have a new possible constellation
// Check if the previous constellation had a lower value and if so, set it to the current one
if (noise > tmp_noise) {
tmp_noise = noise;
tmp_indices.clear();
// tmp save
for (auto &index : indices) {
tmp_indices.push_back(index);
}
}
price= 0;
noise = 0;
indices.clear();
}
// Best constellation found, Print the shopping list
cout << "\Stock.\tNum\Diameter.\Price\n" << endl;
for(unsigned int i = 0; i < tmp_indices.size(); i++) {
cout << stock[tmp_indices[i]]->stock<< "\t";
cout << stock[tmp_indices[i]]->number_fireworks<< "\t";
cout << stock[tmp_indices[i]]->diameter<< "\t";
cout << stock[tmp_indices[i]]->price<< "\t\n";
}
}
We've been told that we should be able to spend exactly 1000€ to get the correct constellation of fireworks. My idea was to add another for loop to iterate through the amount of available packages, but that didn't really work...
This was our first lesson and I'm a bit desperate, because we have only learned how to solve a knapsack problem with 2 constraints and by using a table R.
Edit: Since one user insisted to get a specific question, here it is: Is the idea of using another loop to include the third constraint correct or is there a better/easier way of doing it? Or is it possible that I need a completely different approach for a knapsack with 3 instead of 2 constraints?
Thanks for help in advance

Counting active tasks using start time and duration in C++

The input consists of a set of tasks given in increasing order of start time, and each task has a certain duration associated.
The first line is number of tasks, for example
3
2 5
4 23
7 4
This means that there are 3 tasks. The first one starts at time 2, and ends at 7 (2+5). Second starts at 4, ends at 27. Third starts at 7, ends at 11.
We assume each task starts as soon as it is ready, and does not need to wait for a processor or anything else to free up.
This means we can keep track of number of active tasks:
Time #tasks
0 - 2 0
2 - 4 1
4 - 11 2
11 - 27 1
I need to find 2 numbers:
Max number of active tasks at any given time (2 in this case) and
Average number of active tasks over the entire duration computed here as :
[ 0*(2-0) + 1*(4-2) + 2*(11-4) + 1*(27-11) ] / 27
For this,
I have first found the time when all tasks have come to an end using the below code:
#include "stdio.h"
#include "stdlib.h"
typedef struct
{
long int start;
int dur;
} task;
int main()
{
long int num_tasks, endtime;
long int maxtime = 0;
scanf("%ld",&num_tasks);
task *t = new task[num_tasks];
for (int i=0;i<num_tasks;i++)
{
scanf("%ld %d",&t[i].start,&t[i].dur);
endtime = t[i].start + t[i].dur;
if (endtime > maxtime)
maxtime = endtime;
}
printf("%ld\n",maxtime);
}
Can this be done using Priority Queues implemented as heaps ?
Your question is rather broad, so I am going to just give you a teaser answer that will, hopefully, get you started, attempting to answer your first part of the question, with a not necessarily optimized solution.
In your toy input, you have:
2 5
4 23
7 4
thus you can compute and store in the array of structs that you have, the end time of a task, rather than its duration, for later usage. That gives as an array like this:
2 7
4 27
7 11
Your array is already sorted (because the input is given in that order) by start time, and that's useful. Use std::sort to sort the array, if needed.
Observe how you could check for the end time of the first task versus the start time of the other tasks. With the right comparison, you can determine the number of active tasks along with the first task. Checking whether the end time of the first task is greater than the start time of the second task, if true, denotes that these two tasks are active together at some point.
Then you would do the same for the comparison of the first with the third task. After that you would know how many tasks were active in relation with the first task.
Afterwards, you are going to follow the same procedure for the second task, and so on.
Putting all that together in code, we get:
#include "stdio.h"
#include "stdlib.h"
#include <algorithm>
typedef struct {
int start;
int dur;
int end;
} task;
int compare (const task& a, const task& b) {
return ( a.start < b.start );
}
int main() {
int num_tasks;
scanf("%d",&num_tasks);
task *t = new task[num_tasks];
for (int i=0;i<num_tasks;i++) {
scanf("%d %d",&t[i].start,&t[i].dur);
t[i].end = t[i].start + t[i].dur;
}
std::sort(t, t + num_tasks, compare);
for (int i=0;i<num_tasks;i++) {
printf("%d %d\n", t[i].start, t[i].end);
}
int max_noOf_tasks = 0;
for(int i = 0; i < num_tasks - 1; i++) {
int noOf_tasks = 1;
for(int j = i + 1; j < num_tasks; j++) {
if(t[i].end > t[j].start)
noOf_tasks++;
}
if(max_noOf_tasks < noOf_tasks)
max_noOf_tasks = noOf_tasks;
}
printf("Max. number of active tasks: %d\n", max_noOf_tasks);
delete [] t;
}
Output:
2 7
4 27
7 11
Max. number of active tasks: 2
Now, good luck with the second part of your question.
PS: Since this is C++, you could have used an std::vector to store your structs, rather than a plain array. That way you would avoid dynamic memory allocation too, since the vector takes care that for you automatically.

Need Help in a Project of C++

So this is the actual Problem
Can anyone tell me that how I read the repective Data from the file, and how would I able to store it in variables (without using array) also the code should be generic, That if the number of series will incresed or decresed.. Code will not be affected... I Just can't understand that how would I store sata in variables and how.. Please Help.. :(
Problem
A file contains information of a batsman. Information is no of series
played by the batsman. No of matches played in each series & score in
each match by the batsman. You have to read the data (without using
any array) and find average score and maximum score in all matches of
a series. In the end find overall average score and max score in all
matches.
Input:
Read data from file "cricket.txt". First line contains no of seasons/
series played by the player. Next pair of lines contains matches
played by the batsman followed in next line scores by batsman in
different matches of a season. See sample "cricket.txt"
5
6
93 75 41 40 90 19
5
45 86 30 60 29
3
47 90 33
4
22 2 92 5
5
88 67 96 91 90
First 5 shows player has played 5 seasons/ series
Next 6 show in first series player has played 6 matches
Next line has scores of player in 6 matches
Next 5 show in second series player has played 5 matches
Next line has scores of player in 5 matches
So on in second last line 5 shows player has played 5 matches in 5th
series
Last line has scores of player in 5 matches of last series
You're looking for an array.
int a[10];
// Loop that assigns all elements in array a to 0
for (int i = 0; i < 10; i++)
{
a[i] = 0;
}
// Array b will have all of it's members initialized to 0
int b[10]{};
// You can also assign different values to different elements of the array
b[0] = 6;
b[8] = 2;
// You can then use the array elements in operations
int c = b[0] * b[8];
If you want array like structure without compile time defined size, then use std::vector.
// An empty vector of ints
std::vector<int> d;
// A simple int
int e = 5;
// Push 2 values to the end of the vector
d.push_back(2);
d.push_back(e);
// Use the members for operations
int f = d.at(0) * d.at(1);
Since you've now described the problem you're trying to solve instead of just the problem with the solution you came up with:
You don't need to invent variable names or use arrays to compute averages and maximums.
Here's an example of how you can compute an average of the numbers a user inputs:
float sum = 0;
int elements = 0;
float input = 0;
while (cin >> input)
{
sum += input;
elements += 1;
}
std::cout << "Average: " << sum / elements << std::endl;
It's easy to expand this to also keep track of the maximum value so far.
To expand to the average and maximum of a number of series, add another loop "around" it.

Greedy algorithm error using c++ sets

I've created a greedy algorithm to solve a problem (homework assignment) and since I'm learning c++ I would like to achieve the same thing but using sets.
Basically we submit the homework to an online platform, this platform as some test cases that we don't know of, and we get a score based on that. If we pass all test cases we have 100%;
The problem is like this.
We have an actor that wants to schedule appointments with the fans that answered an online questionnaire about him. Now he wants to choose the fan's that maximizes the sum of points in the questionnaire and respecting the fan's availability. He can see only one fan a day.
We have an input like this:
6
1 1 5
2 2 4
3 1 2
4 3 1
5 1 6
6 2 2
Where the first line is the number of fans and following, in each line, we have the fan id, the fan available days and the fan points achieved in the online questionnaire. I must print the ids of the fans that the actor will see and the sum of combined points of the fans. So for the above input I have the following output:
2
4
5
11
Note that if two fans have the same points, the fan prefered should be the one with the lower ID.
I've started by sorting the fans by the points of the questionnaire (decreasing order) and then by the lower id.
When reading the input, I'm adding the number of days to a set.
My idea was like this:
When iterating over the data, I check if the fan in study days available is in the set. If it is, add this fan and remove the days from the set. If the fan days is not in the set, then get the upper_bound and decrease the iterator to set the fan on the first day lower that the initial day. The algorithm stops wen the set is empty or I iterate all over the fans.
Here is my greedy function:
void greedy() {
fan_id.insert(questionnaire_result[0][0]);
days_available.erase(questionnaire_result[0][1]);
total_questionaire_sum += questionnaire_result[0][2];
int i;
for (i = 1; i < number_of_fans; i++) {
if (days_available.empty()) {
break;
} else if (days_available.count(questionnaire_result[i][1])) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(questionnaire_result[i][1]);
total_questionaire_sum += questionnaire_result[i][2];
} else {
it = days_available.upper_bound(questionnaire_result[i][1]);
if (it == days_available.begin()) {
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
} else if (it == days_available.end()) {
it--;
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
} else {
it--;
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
}
}
}
}
I believe my problem is in this line:
it = days_available.upper_bound(questionnaire_result[i][1]);
I've tested many possibilities and this is working in all my test cases. Unfortunately, we don't have the test cases of the platform.
Does someone see an situation that my code fails? With this I'm getting 90% of the score.
EDIT:
As Edward pointed me out, I've managed to solve the problem like this:
When reading the input added this line of code:
max_days = max_days | questionnaire_result[i][1];
And then did this:
for (int j = 1; j < max_days + 1; j++) {
days_available.insert(j);
}
Problem solved
This input file will cause the program to generate an incorrect result:
2
1 2 6
2 2 5
Both fans are available either day, so it's clear that both fans could be visited and the total output score should be 11. Your algorithm, however, only chooses the first one and outputs a score of 6.