0

Hey guys, recently posted up about a problem with my algorithm.

Finding the numbers from a set which give the minimum amount of waste

Ive amended the code slightly, so it now backtracks to an extent, however the output is still flawed. Ive debugged this considerablychecking all the variable values and cant seem to find out the issue.

Again advice as opposed to an outright solution would be of great help. I think there is only a couple of problems with my code, but i cant work out where.

//from previous post:

Basically a set is passed to this method below, and a length of a bar is also passed in. The solution should output the numbers from the set which give the minimum amount of waste if certain numbers from the set were removed from the bar length. So, bar length 10, set includes 6,1,4, so the solution is 6 and 4, and the wastage is 0. Im having some trouble with the conditions to backtrack though the set. Ive also tried to use a wastage "global" variable to help with the backtracking aspect but to no avail.

SetInt is a manually made set implementation, which can add, remove, check if the set is empty and return the minimum value from the set.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package recursivebacktracking;

/**
 *
 * @author User
 */
public class RecBack {

        int WASTAGE = 10;
        int BESTWASTAGE;
        int BARLENGTH = 10;

    public void work()
    {


         int[] nums = {6,1,2,5};
        //Order Numbers
        SetInt ORDERS = new SetInt(nums.length);
        SetInt BESTSET = new SetInt(nums.length);
        SetInt SOLUTION = new SetInt(nums.length);

        //Set Declarration


        for (int item : nums)ORDERS.add(item);
        //Populate Set

        SetInt result = tryCutting(ORDERS, SOLUTION, BARLENGTH, WASTAGE);
        result.printNumbers();


    }
    public SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft, int waste)
      {


        for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
          {


            int a = possibleOrders.min(); //select next candidate
              System.out.println(a);

            if (a <= lengthleft) //if accecptable
              { 
                solution.add(a); //record candidate
                lengthleft -= a;
                WASTAGE = lengthleft;
                possibleOrders.remove(a); //remove from original set



                if (!possibleOrders.isEmpty()) //solution not complete
                  {
                      System.out.println("this time");
                    tryCutting(possibleOrders, solution, lengthleft, waste);//try recursive call
                    BESTWASTAGE = WASTAGE;
                    if ( BESTWASTAGE <= WASTAGE )//if not successfull
                      {
                        lengthleft += a;
                        solution.remove(a);

                          System.out.println("never happens");
                      }

                  } //solution not complete
              }

          } //for loop

        return solution;

      }




}
Community
  • 1
  • 1
Newb
  • 1
  • 2
  • when debugging it always goes back to the line right after the recursive call, where i set BESTWASTAGE = WASTAGE. This may be causing problems, if so where is the best place to set it? – Newb Apr 21 '11 at 01:10

1 Answers1

1

Instead of using backtracking, have you considered using a bitmask algorithm instead? I think it would make your algorithm much simpler.

Here's an outline of how you would do this:

Let N be number of elements in your set. So if the set is {6,1,2,5} then N would be 4. Let max_waste be the maximum waste we can eliminate (10 in your example).

int best = 0;  // the best result so far

for (int mask = 1; mask <= (1<<N)-1; ++mask) {

    // loop over each bit in the mask to see if it's set and add to the sum
    int sm = 0;
    for (int j = 0; j < N; ++j) {
        if ( ((1<<j)&mask) != 0) {
            // the bit is set, add this amount to the total
            sm += your_set[j];

            // possible optimization: if sm is greater than max waste, then break
            // out of loop since there's no need to continue
        }
    }

    // if sm <= max_waste, then see if this result produces a better one
    // that our current best, and store accordingly
    if (sm <= max_waste) {
        best = max(max_waste - sm);
    }
}

This algorithm is very similar to backtracking and has similar complexity, it just doesn't use recursion.

The bitmask basically is a binary representation where 1 indicates that we use the item in the set, and 0 means we don't. Since we are looping from 1 to (1<<N)-1, we are considering all possible subsets of the given items.

Note that running time of this algorithm increases very quickly as N gets larger, but with N <= around 20 it should be ok. The same limitation applies with backtracking, by the way. If you need faster performance, you'd need to consider another technique like dynamic programming.

For the backtracking, you just need to keep track of which element in the set you are on, and you either try to use the element or not use it. If you use it, you add it to your total, and if not, you proceeed to the next recursive call without increasing your total. Then, you decrement the total (if you incremented it), which is where the backtracking comes in.

It's very similar to the bitmask approach above, and I provided the bitmask solution to help give you a better understanding of how the backtracking algorithm would work.

EDIT OK, I didn't realize you were required to use recursion.

Hint1 First, I think you can simplify your code considerably by just using a single recursive function and putting the logic in that function. There's no need to build all the sets ahead of time then process them (I'm not totally sure that's what you're doing but it seems that way from your code). You can just build the sets and then keep track of where you are in the set. When you get to the end of the set, see if your result is better.

Hint2 If you still need more hints, try to think of what your backtracking function should be doing. What are the terminating conditions? When we reach the terminating condition, what do we need to record (e.g. did we get a new best result, etc.)?

Hint3 Spoiler Alert Below is a C++ implementation to give you some ideas, so stop reading here if you want to work on it some more by yourself.

int bestDiff = 999999999;
int N;
vector< int > cur_items;
int cur_tot = 0;
int items[] = {6,1,2,5};
vector< int > best_items;
int max_waste;

void go(int at) {
  if (cur_tot > max_waste)
    // we've exceeded max_waste, so no need to continue
    return;
  if (at == N) {
    // we're at the end of the input, see if we got a better result and
    // if so, record it
    if (max_waste - cur_tot < bestDiff) {
      bestDiff = max_waste - cur_tot;
      best_items = cur_items;
    }
    return;
  }

  // use this item  
  cur_items.push_back(items[at]);
  cur_tot += items[at];
  go(at+1);

  // here's the backtracking part
  cur_tot -= items[at];
  cur_items.pop_back();

  // don't use this item
  go(at+1);
}

int main() {
  // 4 items in the set, so N is 4
  N=4;

  // maximum waste we can eliminiate is 10
  max_waste = 10;

  // call the backtracking algo
  go(0);

  // output the results
  cout<<"bestDiff = "<<bestDiff<<endl;
  cout<<"The items are:"<<endl;
  for (int i = 0; i < best_items.size(); ++i) {
    cout<<best_items[i]<<" ";
  }
  return 0;
}
dcp
  • 54,410
  • 22
  • 144
  • 164
  • Hi there, thank you for the very detailed response. Unfortunately as this is an assignment i must use a recursive method for the solution. With regards to what you have said about backtracking: solution.add(a); is where i add it to my solution total is that how you mean? Or are you talking about my lengthLeft variable? I was trying to get the backtracking to kick in with the WASTAGE and BESTWASTAGE variables, but im a bit confused as how the flow of the backtrack works for me to implement it. – Newb Apr 21 '11 at 01:28
  • @Newb - See my updated answer, but proceed with caution depending on how much help you want. Good luck! – dcp Apr 21 '11 at 01:54