`

Another Google question - drop glassballs from a building 3

阅读更多
The next step is to find the actually path of floors that we are going through to find the breaking floor. Here is the code to do that.

java 代码
 
  1. package glassball;  
  2.   
  3. import java.util.List;  
  4. import java.util.ArrayList;  
  5.   
  6. /** 
  7.  * For a given building and balls, find out the path of floors we go through 
  8.  * on the way to find the minimal floor where the ball is broken if thrown. 
  9.  */  
  10. public class PathFinder  
  11. {  
  12.     private Building building;  
  13.   
  14.     private GlassBallPuzzle puzzle;  
  15.   
  16.     public PathFinder(Building building, int numOfGlassballs)  
  17.     {  
  18.         this.building = building;  
  19.   
  20.         int totalFloors = building.getNumOfFloors();  
  21.         this.puzzle = new GlassBallPuzzle(numOfGlassballs, totalFloors);  
  22.     }  
  23.   
  24.     public GlassBallPuzzle getPuzzle() { return puzzle; }  
  25.   
  26.     public List findPuzzlePath()  
  27.     {  
  28.         int totalFloors = building.getNumOfFloors();  
  29.         int[][] sums = puzzle.getRecursiveSums();  
  30.   
  31.         // we don't need extra balls. If we don't want this optimization  
  32.         // we have to check whether a floor is higher than building's height,  
  33.         // and ignore them if it's true.  
  34.         int ballIndex = puzzle.getOptimalTrialsAndBalls()[1] - 1;  
  35.         List path = new ArrayList();  
  36.         int baseFloor = 1;  
  37.         generatePathForBallWithIndex(ballIndex, path, baseFloor, totalFloors, sums);  
  38.   
  39.         return path;  
  40.     }  
  41.   
  42.     // This is a recursive call  
  43.     private void generatePathForBallWithIndex(int ballIndex, List path,  
  44.             int baseFloor, int totalFloors, int[][] sums)  
  45.     {  
  46.         int[] floorArray = generateFloorArray(sums, ballIndex, totalFloors);  
  47.   
  48.         for (int i=0; i<floorArray.length; i++)  
  49.         {  
  50.             // -1 here because baseFloor starts with 1.  
  51.             int currentFloor = baseFloor + Math.min(totalFloors, floorArray[i] - 1);  
  52.   
  53.             boolean result;  
  54.             if (ballIndex == 0 &&  currentFloor == totalFloors)  
  55.             {  
  56.                 result = true; // only one ball case 
  57.             }  
  58.             else if (currentFloor < baseFloor + totalFloors)  
  59.             {  
  60.                 result = building.isBrokenIfThrowAt(currentFloor);  
  61.                 path.add(new Trial(currentFloor, ballIndex, result, false));  
  62.             }  
  63.             else  
  64.             {  
  65.                 result = true// we have been here, no point to do it again.  
  66.             }  
  67.   
  68.             if (result)  
  69.             {  
  70.                 if (i > 0) baseFloor += floorArray[i-1];  
  71.   
  72.                 int floorsBetween = currentFloor - baseFloor;  
  73.   
  74.                 if (ballIndex - 1 <= 0// 0 or 1  
  75.                 {  
  76.                     // try from bottom, one floor at a time  
  77.                     for (int k=baseFloor; k<baseFloor+floorsBetween; k++)  
  78.                     {  
  79.                         if (k <= 0continue// this happens when floor 1 is broken.  
  80.                         boolean stepResult = building.isBrokenIfThrowAt(k);  
  81.                         path.add(new Trial(k, ballIndex - 1, stepResult, false));  
  82.                         if (stepResult) return;  
  83.                     }  
  84.   
  85.                     // this indicate the last broken one is the floor  
  86.                     // if there is no broken one, then we need to add the last floor  
  87.                     boolean hasBroken = false;  
  88.                     boolean allBroken = true;  
  89.                     for (int j=0; j<path.size(); j++)  
  90.                     {  
  91.                         Trial trial = (Trial)path.get(j);  
  92.                         if (trial.isBroken()) hasBroken = true;  
  93.                         else allBroken = false;  
  94.                     }  
  95.   
  96.                     if (!hasBroken) path.add(new Trial(currentFloor, ballIndex, truetrue));  
  97.                     if (allBroken) path.add(new Trial(currentFloor, ballIndex, truetrue));  
  98.                     return;  
  99.                 }  
  100.                 else  
  101.                 {  
  102.                     // now try on ballIndex - 1 array.  
  103.                     if (floorsBetween > 0)  
  104.                     {  
  105.                         generatePathForBallWithIndex(ballIndex - 1, path,  
  106.                             baseFloor, floorsBetween, sums);  
  107.                         return;  
  108.                     }  
  109.                 }  
  110.             }  
  111.             // continue  
  112.         }  
  113.     }  
  114.   
  115.     // This method is similar to the one in GlassBallPuzzle, but is dynamic  
  116.     // since the underlying sum array varies - depends on totalFloors variable.  
  117.     private int[] generateFloorArray(int[][] sums, int ballIndex, int totalFloors)  
  118.     {  
  119.         if (ballIndex == 0)  
  120.         {  
  121.             return sums[0];  
  122.         }  
  123.   
  124.         // find the end element not to exceed totalFloors  
  125.         int[] sumArray = sums[ballIndex];  
  126.         int index = 0;  
  127.         for (int j=0; j<sumArray.length; j++)  
  128.         {  
  129.             // The equal sign is corresponding to the last trial  
  130.             // when the ball is broken.  
  131.             if (sumArray[j] >= totalFloors)  
  132.             {  
  133.                 index = j;  
  134.                 break;  
  135.             }  
  136.         }  
  137.   
  138.         // now start from the end element, sum up going to the beginning;  
  139.         sumArray = sums[ballIndex - 1];  
  140.         int[] floors = new int[index + 1];  
  141.         int total=0;  
  142.         for (int j=0; j<=index; j++)  
  143.         {  
  144.             total += sumArray[index - j];  
  145.             floors[j] = total;  
  146.         }  
  147.   
  148.         return floors;  
  149.     }  
  150. }  


The last method is to generate series (A), (B), ... dynamically. The main code is a recursion.

Here we use two other classes, Building and Trial. Building is to define the number of floors and the broken floor, which will be used for testing purpose. The Trial class is to record each trial, plus a flag to indicate whether this is a logic conclusion or not, as we discussed in the previous post listed in (i) and (ii).

java 代码
  1. package glassball;
  2. /**
  3. * To hold the state of each trial
  4. */
  5. public class Trial
  6. {
  7. private int floor;
  8. private int ballNum;
  9. private boolean broken;
  10. private boolean isDeducted = false;
  11. public Trial(int floor, int ballNum, boolean broken, boolean isDeducted)
  12. {
  13. this.floor = floor;
  14. this.ballNum = ballNum;
  15. this.broken = broken;
  16. this.isDeducted = isDeducted;
  17. }
  18. public int getFloor() { return floor; }
  19. public int getBallNum() { return ballNum; }
  20. public boolean isBroken() { return broken; }
  21. public boolean isDeducted() { return isDeducted; }
  22. public String toString()
  23. {
  24. return "(f=" + floor + ", b=" + ballNum + ", " + (broken ? "broken" : "whole")
  25. + ", " + (isDeducted ? "deducted" : "tried") + ")"; }
  26. public boolean equals(Object obj)
  27. {
  28. if ( !(obj instanceof Trial) ) return false;
  29. Trial trial = (Trial)obj;
  30. return this.floor == trial.floor && this.ballNum == trial.ballNum &&
  31. this.broken == trial.broken && this.isDeducted == trial.isDeducted;
  32. }
  33. }

and

java 代码
  1. package glassball;
  2. /**
  3. * Building with floors.
  4. */
  5. public class Building
  6. {
  7. private int numOfFloors;
  8. // the lowest floor where the ball is broken if thrown.
  9. // This field is sealed inside this class.
  10. private int ballbreakingfloor;
  11. public Building(int numOfFloors, int ballbreakingfloor)
  12. {
  13. this.numOfFloors = numOfFloors;
  14. this.ballbreakingfloor = ballbreakingfloor;
  15. }
  16. public int getNumOfFloors() { return numOfFloors; }
  17. public boolean isBrokenIfThrowAt(int floor) { return floor >= ballbreakingfloor; }
  18. }


The test cases are a little complex, which is in the next post.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics