Assign the work for 2 people so that the time is minimum - c++

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.

Related

Best way to find difference between two values in a cyclic system?

Take for example time: if we have the starting hour and ending hour, what's the best way to find the number of hours between them?
If we take a 12-hour clock, we'd get the following results
from 1 to 5 = 4
from 11 to 1 = 2
What is the most efficient way to do that?
Assuming a 12 hour clock, the number of hours from a to b can be calculated as:
difference = ((b + 12) - a) % 12;
This also assumes that a and b are both in the range [1, 12]. In case they are not, you can do:
a %= 12;
b %= 12;
before doing the difference calculation.
Assuming input already in range 1-12, you might do
return b - a + (b < a) * 12;
benchmark showing a 2 times performance gain over cigien's solution.

need help for codejam question "PARENTING PARTNERSHIP"

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.

Trying to find root mean square of two rows in array

i am working through an EDX course on computer programming. I have come to this problem and dont know how to work through it. im not looking for an answer but more a point in the right direction.
so the question gives you a 2D array. two columns and N amount of rows. the N is the number of students. each column is the grade of first test and then the second is the grade of the second test. I am asked to find the root mean square of two seperate kids and compare them and then return a number based off the comparison. The question gives you this formula
RMS = (0.5×(midsem_marks2 + endsem_marks2))0.5
I know how to get the appropriate marks using array[index 1(firsttest)] etc and then how to compare them. However, i am clueless on how to write that formula. any help would be great. Thanks in advance.
code I have
float RMSi1 = sqrt(.5*((marksarray[index1][0]*marksarray[index1][0])+(marksarray[index1][1])*(marksarray[index1][1])));
float RMSi2 = sqrt(.5*((marksarray[index2][0]*marksarray[index2][0])+(marksarray[index2][1])*(marksarray[index2][1])));
if(RSMi1>RSMi2){
return -1;
}
if(RSMi1<RSMi2){
return 1;
}
if(RSMi1==RSMi2){
return 0;
}
I'm getting an error that the RSMi1 and 2 are not declared in the if statements
Input marksarray:
1 2
1 60 20
2 60 20
3 30 40
4 10 90
5 90 30
6 0 100
7 60 20

SIGSEGV Error on Dynamic Programming - CodeChef

Hope you all are having a great day!
I love programming, but these past days I am having sleepless nights, with CodeChef always returning SIGSEGV errors on my Dynamic Programming solutions.
I am solving this question right now. Here's the question -
In Byteland they have a very strange monetary system. Each Bytelandian
gold coin has an integer number written on it. A coin n can be
exchanged in a bank into three coins: n/2, n/3 and n/4. But these
numbers are all rounded down (the banks have to make a profit). You
can also sell Bytelandian coins for American dollars. The exchange
rate is 1:1. But you can not buy Bytelandian coins. You have one gold
coin. What is the maximum amount of American dollars you can get for
it?
Input
The input will contain several test cases (not more than 10). Each
testcase is a single line with a number n, 0 <= n <= 1 000 000 000. It
is the number written on your coin. Output
For each test case output a single line, containing the maximum amount
of American dollars you can make. Example
Input: 12 2
Output: 13 2 You can change 12 into 6, 4 and 3, and then change these
into $6+$4+$3 = $13. If you try changing the coin 2 into 3 smaller
coins, you will get 1, 0 and 0, and later you can get no more than $1
out of them. It is better just to change the 2 coin directly into $2.
Now I know that it's very easy. And I did get stuck initially when I was declaring a big 10^9 integer long array (Over 1GB of memory..whoo!), but coming back to my senses - I decided to do memoization till 10001, and after that simple recursion. But still - I am making a mistake, and it's giving SIGSEGV error.
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n[100001];
long long calc(long long x) {
if (x < 10001) {
if(n[x] != 0) return n[x];
n[x] = max(x, calc(x/2) + calc(x/3) + calc(x/4));
return n[x];
}
else return max(x, calc(x/2) + calc(x/3) + calc(x/4));
}
int main() {
memset(n, 0, sizeof(n));
n[1] = 1;
n[2] = 2;
n[3] = 3;
n[4] = 4;
n[5] = 5;
n[6] = 6;
for (int i = 7; i < 10001; i++)
n[i] = calc(i);
int t = 10;
while (t--) {
long long c;
scanf("%lld", &c);
printf("%lld\n", calc(c));
}
return 0;
}
I have solved some previous questions too - and all of them gave me this error once or twice. I know this error means that I am trying to access memory that hasn't been allocated, but what is wrong in my approach that I always get this error?
The problem is with the corner case n=0.
calc(0) recurses indefinitely because 0<10001 and n[0]=0. You need to add the terminating condition that calc(0)=0.
Takeaways:
Always check your programming competition solutions on corner cases.
Always ensure that your recursion does not result in an infinite loop.

Wrong Answer in SUBSEQ spoj

I was solving Counting Subsequence Problem in spoj, but getting Wrong Answer. here is the link http://www.spoj.com/problems/SUBSEQ/
Here is my code
#include<stdio.h>
#include<cmath>
#include<algorithm>
int main(){
int t,n;
scanf("%d",&t);
while(t-->0){
scanf("%d",&n);
long arr[n+1];
for(int i=0;i<n;i++){
scanf("%ld",&arr[i]);
}
long sum=arr[0];
int start=0;
long ans=0;
for(int i=1;i<=n;i++){
while(sum>47 && start<i-1){
sum-=arr[start];
start++;
}
if(sum==47)
ans+=1;
if(i<n)
sum+=arr[i];
}
printf("%ld\n",ans);
}
}
Please help me find the error ..
You code will fail the following test case (at least):
1
4
47 -47 48 -1
Your programs gives the answer as 1, where as the answer should be 3, where 3 sequences as follows:
47 -47 48 -1 [The entire sequence]
47 [1st element only]
48 -1 [3rd plus 4th elements]
So, clearly, you've got bugs.
PS: BTW, why are you declaring an array of n+1 items: long arr[n+1]; when you are never going to reference arr[n]? (in fact that item won't even exist)
[Edit]#: Adding explanation for the above use case
How about this - Its easier than you think :-)
Scan the numbers serially. For each number encountered, add it to sum found so far.
Keep a map of number of times the sum (so far) has been found.
Now, to make a total of 47, all we need is to find a number, which when subtracted from the sum so far should give number 47. This is required because if we subtract such number from sum found so far, it would yield 47 obtained from summation of some sequence(s) of contiguous numbers.
Take the above example, 47 -47 48 -1
Initialize a map with number 0 having count = 0 (That's to say that we have found no sum so far exactly once - since we are at the begining)
Scanning the list from the beginning, take number 47, sum so far, say, s = 47. We do 2 things:
map(47) = 1 (since we've found sum so far = 47 for first time).
Now, we need to find number of times, we've can find s-47 = 0 (which is 1). So, answer so far = map(0) = 1
Take next number, -47. Sum so far, s = 0
map(0) = 1 so far, so no map(0) becomes = 2
We need to find number of occurrences of s-47 = -47. Which = 0. So answer so far = answer so far + 0 (remains = 1)
Take next number, 48, sum so far, s = 48
map(48) = 1
We need to find number of occurrences of s-48 = -1. Which = 0. So answer so far = answer so far + 0 (remains = 1)
Take last number, -1, sum so far, s = 47
map(47) = 1 (in step 2.1), so now map(47) becomes = 2
We need to find number of occurrences of s-47 = 0. Which = 2 (in step 3.1). So answer so far = answer so far + 2 = 3
So final answer = 3
It should be fairly trivial to code this.