7

Let's say we're given N jobs and K workers to do those jobs. But for some jobs we need 2 employees, while for some we need just one. Also the employees can't do all jobs. For example worker 1 can do jobs 1,2 and 5, while not jobs 3 and 4. Also if we hire worker 1 to do job 1, then we want him to do jobs 2 and 5, since we've already paid him.

So for example let's say we have 5 jobs and 6 workers. For jobs 1,2 and 4 we need 2 men, while for jobs 3 and 5 we need just one. And here's the list of the jobs every worker can do and the wage he requires.

Worker 1 can do jobs 1,3,5 and he requires 1000 dollars. 
Worker 2 can do jobs 1,5 and he requires 2000 dollars. 
Worker 3 can do jobs 1,2 and he requires 1500 dollars. 
Worker 4 can do jobs 2,4 and he requires 2500 dollars. 
Worker 5 can do jobs 4,5 and he requires 1500 dollars. 
Worker 6 can do jobs 3,5 and he requires 1000 dollars. 

After little calculation and logical thinking we can conclude that we have to hire workers 1,3,4 and 5, which means that the minimum wage we need to pay is: 1000+1500+2500+1500=5500 dollars.

But how we can find an efficient algorithm that will output that amount? This somehow reminds me of the Hungarian Algorithm, but all those additional constrains makes it impossible for me to apply it.

Stefan4024
  • 694
  • 1
  • 10
  • 21
  • Do you actually need to solve this problem? It looks like a homework problem, and you're trying to perform a complex optimization. If so, do it the slow/simple way and turn it in. I suspect this discussion is going to be complex and/or time consuming. – Mooing Duck Apr 09 '15 at 20:52
  • @MooingDuck It's not a homework problem, it's a past contest question. – Stefan4024 Apr 09 '15 at 20:53
  • "Also if we hire worker 1 to do job 1, then we want him to do jobs 2 and 5, since we've already paid him." Wouldn't you pay him separately for each job? Or are you saying he will do all three jobs for $1000? – Yay295 Apr 09 '15 at 22:31
  • @Yay295 He will do all the three jobs for $1000, but we can't hire him to do just one job for $333,33. To make it more clear let's say we pay him a daily wage. But in that day he does all kind of a jobs (of course, all the ones he can do). And at the end of a day we want all the jobs done. – Stefan4024 Apr 09 '15 at 22:34
  • How large can N and K be? – kraskevich Apr 09 '15 at 23:40
  • @kraskevich N <= 8, while K<= 60 – Stefan4024 Apr 09 '15 at 23:41
  • Does saying that worker 1 can do 3 different jobs imply that he also has time for all of those jobs? If it would take a person for example 0,5 days to complete a job, worker 1 could do any of the 2 jobs he is capable of doing, but you would still need to hire another worker for the last one. – H W Apr 10 '15 at 08:49
  • Worker 1 WILL have time to do all 3 jobs in a day. Think of it like this. Let's say we have 5 box and we want them to move to store. Worker 1 can lift only box 1,3,5, while he can't lif box 2,4 for some reasons. Also some of the box are heavy and they require 2 people to lift it. When we hire worker 1 to lift box 1, he can always lift boxes 3 and 5. We're not paying a worker per box (or per job). – Stefan4024 Apr 10 '15 at 15:41

1 Answers1

2

We can represent a state of all jobs as a number in a ternary system(2-two people remaing, 1-one person remaining and 0 if it is already done). Now we can compute f(mask, k) = the smallest cost to hire some workers among the first k in such a way that the state of remaining jobs is mask. Transitions are as follows: we either go to (mask, k + 1)(not hiring the current worker) or we go to (new_mask, k + 1)(in this case we pay this worker his salary and let him do all the jobs he can). The answer is f(0, K).

The time complexity is O(3^N * K * N).

Here is an idea how to optimize it further(and get rid of the N factor). Let's assume that the current mask is mask and the man can do jobs from another mask'. We could actually simply add mask to mask', but there is one problem: the positions where there was 2 in the mask and 1 in mask' will get broken. But we can fix: for each mask, let's precompute a binary mask allowed_mask that contain all position where the digit is not 2. For each man and for each allowed_mask we can precompute that mask' value. Now each transition is just one addition:

for i = 0 ... k - 1
    for mask = 0 ... 3^n - 1
        allowed_mask = precomputed_allowed_mask[mask]
        // make a transition to (i + 1, mask + add_for_allowed_mask[i][allowed_mask])
        // make a transition to (i + 1, mask)

Note that there are only 2^n allowed masks. So the time complexity of this solution is O(3^N * N + T * 2^N * K * N + T * 3^N * K)(the first term is for precomputing allowed_masks for all ternary mask, the second one is for precomputing mask' for all allowed_masks and people, and the last is for dp itself).

kraskevich
  • 18,368
  • 4
  • 33
  • 45
  • That's nice thinking. But do you think that O(3^N*K*N) algorithm will be performed in 1 sec (the problem's time limit) with N=8 and K=60 as maximum value. I've used mask in solving a travelling salesman problem. I controlled the mask by using bit shifting, but here it's gonna be a little bit more difficult since we're using ternary system. I thought about creating a special funtion that will convert the number to ternary system (lets say 10 will stand for the mask 00101). Any thoughts on this? – Stefan4024 Apr 10 '15 at 16:05
  • Also I would need a two-dimensional array of size 60x3^8(6561) I would need even more time to fill it with INT_MAX values. So do you think this will efficiently solve the problem? – Stefan4024 Apr 10 '15 at 16:11
  • @Stefan4024 (3^8) * 60 * 8 = 3149280, which is a very small number. It should easily run in under 1 second(at least in languages like C++, Java or something else with similar performance). – kraskevich Apr 10 '15 at 16:13
  • @Stefan4024 And yes, using a special function to convert a number from/to ternary looks like a good way to go. – kraskevich Apr 10 '15 at 16:14
  • Also this problem has an advanced variation, when K<=200. How about that? Then (3^8)*8*200=10497600 – Stefan4024 Apr 10 '15 at 16:15
  • @Stefan4024 I don't know the parameters of the server, but it still looks good enough for 1 sec. – kraskevich Apr 10 '15 at 16:15
  • I'll give it a try and will inform you about the success of the solution. – Stefan4024 Apr 10 '15 at 16:16
  • I've submitted my code in C++ and the code passed the easier problem with N<=8 and K<=60. But when I submitted that code in the more advanced problem the code passed just 6 of the 20 test cases. For the rest 14 test cases the time limit has been exceeded. Furthermore, for one of the passed test case it took the system 0.999 seconds to compile the code. – Stefan4024 Apr 10 '15 at 17:58
  • @Stefan4024 Does this problem has multiple test cases per input? Are you sure that you implemented it optimally? – kraskevich Apr 10 '15 at 18:17
  • Yes it has 20 different test cases. Also I implemented the algorithm as you've said. BTW I can send you a code from it. – Stefan4024 Apr 10 '15 at 19:02
  • @Stefan4024 I have a description of a faster solution. – kraskevich Apr 10 '15 at 19:35