Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share Fruits Fairly (Dynamic Programming)

I'm having a very hard time trying to figure out how to solve this problem efficiently. Let me describe how it goes:

"A hard working mom bought several fruits with different nutritional values for her 3 kids, Amelia, Jessica and Bruno. Both girls are overweight, and they are very vicious and always leave poor Bruno with nothing, so their mother decided to share the food in the following manner:

  • Amelia being the heaviest one gets the most amount of Nutritional Value
  • Jessica gets an amount equal or less than Amelia
  • Bruno gets an amount equal or less than Jessica, but you need to find a way to give him the highest possible nutritional value while respecting the rule ( A >= J >= B )"

Note: The original problem is described differently but the idea is the same, I don't want my classmates to find this post when they google for help hehe.

One of the test cases given by my teacher is the following:

The fruit list has the following values { 4, 2, 1, 8, 11, 5, 1}

Input:
7   -----> Number of Fruits
4 2 1 8 11 5 1 ----> Fruits Nutritional Values

Output:
1 11  ---->  One fruit, their nutritional values sum for Amelia
5     ---->  Position of the fruit in the list
3 11  ---->  Three fruits, their nutritional values sum for Jessica
1 2 6 ---->  Position of the fruits in the list
3 10  ---->  Three fruits, their nutritional values sum for Bruno
3 4 7 ---->  Position of the fruits in the list

Note: I am aware that there are several ways of diving the fruits among the kids, but it doesn't really matter as long as it follows the rule A >= J >= B.

At first I made an algorithm that generated all the subsets, each one had their sums, and the positions that were in use. That method was quickly discarded because the list of fruits can have up to 50 fruits, and the subset algorithm is O(2^n). I ran out of memory.

The second idea that I have is to use Dynamic Programming. In the columns header I would have the positions of the Fruit's List, in the row header the same, it's kind of hard to explain with letters so I'll ahead an do the table for the previous example { 4, 2, 1, 8, 11, 5, 1}.

   00 01 02 03 04 05 06 07
00 
01
02
03
04
05
06
07

Each time we advance to the row below we add the positions 1,2,3,...,7

   00 01 02 03 04 05 06 07
00 00                     <---No positions in use  
01 04                     <---RowPosition 1 + Column Position(Column 0) (4+0)
02 06                     <---RowPosition 1 + RowPosition 2 + Column Position (4+2+0)
03 07                     <---RP(1) + RP(2) + RP(3) + CP(0) (4+2+1+0)
04 15                     <--- (4+2+1+8+0)
05 26
06 31
07 32                     <--- (4+2+1+8+11+5+1+0)

Now that you know how it goes lets add the first row

   00 01 02 03 04 05 06 07
00 00 04 02 01 08 11 05 01   <-- Sum of RP + CP                     
01 04 00 06 05 12 15 09 05   <-- Sum of RP(0..1) + CP                      
02 06                     
03 07                     
04 15                     
05 26
06 31
07 32                     

I put the 00 because the 1st position is already in use. The completed table would look like this.

   00 01 02 03 04 05 06 07
00 00 04 02 01 08 11 05 01                      
01 04 00 06 05 12 15 09 05                         
02 06 00 00 07 14 17 11 07                 
03 07 00 00 00 15 18 12 08                  
04 15 00 00 00 00 26 20 16                    
05 26 00 00 00 00 00 31 27
06 31 00 00 00 00 00 00 32
07 32 00 00 00 00 00 00 00    

Now that we have the table. I divide the sum of the Nutritional Values by the amount of kids, 32/3 = 10.6667, the ceiling would be 11. I try to check for 11, if it's in the table, I choose it and mark the position of the row and columns of the tables as used, then I would try to check for 11 again, if it's in the table I choose it otherwise look the 10, or 9, etc until I find it. Afterwards I would mark the respective positions as used then sum the unused positions to get Bruno's fruits.

I know that there has to be better way to do this because I found a flaw in my method, the table only has the sum of a few subsets. So maybe that will be detrimental in a few test cases. Maybe a 3D Memoization Cube?, I think it would consume too much memory, and I have a limit too 256MB.

Wow, I didn't realize I typed this much x.X. I hope I don't get a lot of tl; dr. Any help / guide would be greatly appreciated :D

EDIT: I made the code that generates the table in case anyone wants to try it out.

static void TableGen(int[] Fruits)
    {
        int n = Fruits.Length + 1;
        int[,] memo = new int[n, n];

        for (int i = 1; i < n; i++)
        {
            memo[0, i] = Fruits[i - 1]; 
            memo[i, 0] = memo[i - 1, 0] + Fruits[i - 1]; 

            for (int j = i + 1; j < n; j++)
                memo[i, j] = memo[i, 0] + Fruits[j - 1];               
        }


        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                Console.Write("{0:00} ", memo[i, j]);

            Console.WriteLine();
        }

    }
like image 829
Julian J. Tejera Avatar asked Jul 01 '12 04:07

Julian J. Tejera


1 Answers

A slightly computationally intensive way would be to assign the fruit in a round robin way, starting with the highest nutritional value for amelia.
From there, progressively loop through the fruit from lowest nutritional value held by amelia, and try each combination of either (a) giving the fruit to jessica, or (b) swapping the fruit with one held by jessica, while still satisfying the rule. Then apply the same method to jessica and bruno. Repeat these 2 loops until no more swaps or gives are possible.
Slightly trickier, but potentially faster, would be to simultaneously give/swap to jess/bruno. For each 2 pieces of fruit that A holds, you would have 4 options to try, with more if you at the same time try and balance J & B.

For a faster algorithm, you could try asking at the mathematics stack exchange site, as this is very much a set-theory problem.

like image 95
3Pi Avatar answered Oct 30 '22 17:10

3Pi