Проблема с рекурсивной упаковкой коробок в контейнер - PullRequest
1 голос
/ 18 февраля 2020

У меня проблема с кодом, который я пишу, который должен взять список ящиков разного размера и упаковать их в один большой контейнер.

Основной метод, который должен реализовывать решение, называется fillContainerBox(). У меня есть базовое c вложенное выражение if, которое будет работать для упаковки первых нескольких коробок, но код не выполняется, когда необходимо распаковать более 1 коробки.

/**Container Box Class which sorts using recursion
 * 
 * @author Richard McCormick
 */
  public class ContainerBoxClass extends java.lang.Object
  {
  private static int CLEAR_BOX = 102;
  private static int FILL_BOX = 101;
  private static final char DEFAULT_FIELD_CHAR = 45;
  private static final int MAX_NUM_BOXES = 26;
  private static final int NO_BOXES_AVAILABLE = -1;
  private BoxClass[] boxList = new BoxClass[MAX_NUM_BOXES];
  private char[][] containerBoxField;
  private int containerBoxHeight = 0;
  private int containerBoxWidth = 0;
  private int numBoxesAvailable = 0;

  //Shows what you are doing
  private boolean displayFlag = false;

  /**Default constructor class
   * @param initBoxHeight - Height of container
   * @param initBoxWidth  - Width of container
   */
  ContainerBoxClass(int initBoxHeight, int initBoxWidth)
  {
     containerBoxHeight = initBoxHeight;
     containerBoxWidth = initBoxWidth;
     containerBoxField = new char[containerBoxWidth][containerBoxHeight];

     //Populates field with empty values
     for (int y = 0; y < containerBoxHeight; y++)
        {
           for (int x = 0; x < containerBoxWidth; x++)
              {
                 containerBoxField[x][y] = DEFAULT_FIELD_CHAR;
              }
        }

     displayFlag = false;
  }

  /**Adds a new box to list of boxes
   * @param boxWidth
   * @param boxHeight
   * @return success
   */
  public boolean addBoxToList(int boxWidth, int boxHeight)
  {
     //Initialize return
     boolean success = false;

     //Checks that there is room
     if (numBoxesAvailable < MAX_NUM_BOXES)
        {
           //Creates a new box
           BoxClass tempBox = new BoxClass(boxWidth, boxHeight);
           tempBox.unsetUsedState();

           //Increments available boxes
           boxList[numBoxesAvailable] = tempBox;
           numBoxesAvailable++;

           //Success
           success = true;
        }


     return success;
  }

  /**Checks location to see if box will fit
   * 
   * @param testLocation  - Point class
   * @param testBox       - Box class
   * 
   * @return fits         - Boolean indicator
   */
  private boolean checkForFitInField(PointClass testLocation, BoxClass testBox)
  {
     boolean fits = false;

     //Dimensions of testBox
     int testWidth = testBox.getWidth();
     int testHeight = testBox.getHeight();

     //Position of test point
     int testLocX = testLocation.getXPos();
     int testLocY = testLocation.getYPos();

     System.out.println("Test location: " + testLocX + " " + testLocY);

     //Booleans to see if box is out of bounds or not
     boolean inBoundsX = ((testLocX + testWidth) < containerBoxWidth);
     boolean inBoundsY = ((testLocY + testHeight) < containerBoxHeight);

     //If size fits within the container at desired location
     if (inBoundsX && inBoundsY)
        {
           int numOccupied = 0;

           //Iterates through location to determine if empty
           for (int ycounter = testLocY; ycounter < (testLocY + testHeight); ycounter++)
              {
                 for (int xcounter = testLocX; xcounter < (testLocX + testWidth); xcounter++)
                    {
                       //If there is something in location bounds, location not empty
                       if (containerBoxField[xcounter][ycounter] != DEFAULT_FIELD_CHAR)
                          {
                             numOccupied++;
                          }
                    }
              }

           if (numOccupied == 0)
              {
                 fits = true;
              }
        }

     return fits;
  }

  /**Displays the items in box
   * 
   */
  public void displayField()
  {
     String row;

     //Prints field from top down, to preserve order/location
     for (int height = containerBoxHeight - 1; height >= 0; height--)
        {
           //Clears row each iteration
           row = "";

           //Iterates through columns in row
           for (int width = 0; width < containerBoxWidth; width++)
              {
                 //Checks to see if location is empty or not
                 if (containerBoxField[width][height] != DEFAULT_FIELD_CHAR)
                    {
                       row += " X ";
                    }
                 else
                    {
                       row += " " + DEFAULT_FIELD_CHAR + " ";
                    }
              }
           System.out.println(row);
        }
     System.out.println("===================================");
  }

  /**Fills a location in container box with a given box
   * 
   * @param boxLocation   - Location to pack box
   * @param fillBox       - Box to be packed
   * @param clearFlag     - Indicates if box is to be packed or removed
   */
  public void fillBoxLocation(PointClass boxLocation, BoxClass fillBox, int clearFlag)
  {  
     //Sets the starting and end positions for X-Axis
     int xstart = boxLocation.getXPos();
     int xend = xstart + fillBox.getWidth();

     //Sets the starting and end positions for Y-Axis
     int ystart = boxLocation.getYPos();
     int yend = ystart + fillBox.getHeight();

     //Output for testing
     System.out.println("Attempting to fill box of size: " + fillBox.getWidth() + " " + fillBox.getHeight());
     System.out.println("At location: " + xstart + " " + ystart);

     //Iterates through each row
     for (int ycounter = ystart; ycounter < yend; ycounter++)
        {
           //Iterates through each column
           for (int xcounter = xstart; xcounter < xend; xcounter++)
              {
                 //If clearFlag is set to fill box
                 if (clearFlag == FILL_BOX)
                    {
                       //Fill box
                       containerBoxField[xcounter][ycounter] = (char)FILL_BOX;
                       fillBox.setUsedState();
                    }

                 //Otherwise, erase box
                 else if (clearFlag == CLEAR_BOX)
                    {
                       containerBoxField[xcounter][ycounter] = (char)DEFAULT_FIELD_CHAR;
                       fillBox.unsetUsedState();
                    }
              }
        }
  }

  /**Attempts to fill the container class with boxes
   * 
   * @return success   - Boolean value indicating operation success
   */
  public boolean fillContainerBox()
  {
     boolean success = false;

     int currentBoxIndex = 0;
     int previousBoxIndex = -1;
     BoxClass currentBox;
     BoxClass previousBox = new BoxClass();
     PointClass currentLocation;
     PointClass previousLocation = new PointClass();

     while (findNextUnusedBoxIndex(0) != NO_BOXES_AVAILABLE)
        {
           currentBoxIndex = findNextUnusedBoxIndex(0);
           currentBox = boxList[currentBoxIndex];
           currentLocation = findNextOpenLocation();
           BoxClass nextBox = boxList[currentBoxIndex + 1];

           if (checkForFitInField(currentLocation, currentBox))
              {
                 fillBoxLocation(currentLocation, currentBox, FILL_BOX);
                 PointClass nextLoc = new PointClass();
                 nextLoc = findNextOpenLocation();
                 if (checkForFitInField(nextLoc, nextBox) != true)
                    {
                       fillBoxLocation(currentLocation, currentBox, CLEAR_BOX);
                       fillBoxLocation(currentLocation, nextBox, FILL_BOX);
                    }
              }


           previousLocation = currentLocation;
           previousBox = currentBox;

           if (displayFlag)
              {
                 displayField();
              }
        }

     return success;
  }

  /**Finds the next open location in the container box
   * 
   * @return openLocation   - PointClass object containing first open location
   */
  private PointClass findNextOpenLocation()
  {
     //Instantiates return variable as empty PointClass
     PointClass openLocation = new PointClass();

     //Boolean value which indicates whether location has been found
     boolean hasLocation = false;

     //Iterates through each row
     for (int ycounter = 0; ycounter < containerBoxHeight; ycounter++)
        {
           //Iterates through each column
           for (int xcounter = 0; xcounter < containerBoxWidth; xcounter++)
              {
                 //If item at current location is empty, and no item has yet been found
                 if (containerBoxField[xcounter][ycounter] == DEFAULT_FIELD_CHAR && hasLocation == false)
                    {
                       //Set current location as first open location
                       openLocation.setXPos(xcounter);
                       openLocation.setYPos(ycounter);

                       //Indicate that location has been found
                       hasLocation = true;
                    }
              }
        }

     //Return the open location
     return openLocation;
  }

  /**Finds the next unused box in boxList, starting at provided index
   * 
   * @param startAtIndex  - Index to begin searching at
   * @return indexFinal   - Index of first unused box
   */
  private int findNextUnusedBoxIndex(int startAtIndex)
  {
     //Sets up return and internal vars
     int indexFinal = NO_BOXES_AVAILABLE;
     int counter = startAtIndex;

     //Iterates through available boxes
     while (counter < numBoxesAvailable)
        {
           //If box has already been used, skip and increment
           if (boxList[counter].isUsed())
              {
                 counter++;
              }

           //Otherwise, return unused box index & terminate
           else
              {
                 indexFinal = counter;
                 counter = numBoxesAvailable;
              }
        }

     //Return unused box index
     return indexFinal;
  }

  /**Sets display flag
   * 
   * @param setState   - Boolean value to set displayFlag to
   */
  public void setDisplayFlag(boolean setState)
  {
     //If display flag is not already equal to set state
     if (setState != displayFlag)
        {
           //Set new flag state
           displayFlag = setState;
        }
  }
}

Пожалуйста, извините за мой грязный код. Я пытался найти решение, но не нашел его.

1 Ответ

0 голосов
/ 19 февраля 2020

Рассмотрите возможность использования жадного алгоритма .

Вы начинаете с коробки (назовем ее пакет ), которая будет содержать другие поля. Из ящиков, которые нужно поместить в пакет , сначала поместите самый большой ящик (Вы можете получить его, отсортировав список ящиков по объему в порядке убывания, например, [самый большой ящик, второй по величине, .. ., самая маленькая коробка]). В зависимости от размера этого поля, пакет может иметь некоторый объем, который мы можем заполнить другими ящиками. Теперь в оставшихся томах мы можем попробовать поместить второе по величине поле, следуя тому же методу, который использовался для заполнения пакета . Все, что нам нужно сделать, это разделить оставшееся пространство пакета и рассматривать эти разделы как меньшие версии всей проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...