所以我有如下的小清单,代表仓库位置:
30 09 05
30 04 05
30 02 01
31 07 05
31 07 04
31 03 05
31 03 06
31 09 05
31 02 05
第一列表示位置行,第二列表示位置高度,第三列表示位置位置(向前)
我需要计算叉车操作员根据不同位置检索不同物品的最佳路径(行,位置,高度)
为此我使用Collection.sort首先按行排序列表然后按位置(向前)排序,最后按高度排序。
行按成对分组,因为操作员从偶数行(操作员左侧)和奇数行(操作员右侧)检索项目而不移动叉车位置和高度
是有意义的我几乎在那里我只需要一只手,当pos向前移动时我需要保持相同的高度并获得最接近的高度,而不是从底部开始,这会让操作员失去时间上下移动
以下是代码:
Collections.sort(unoptimizedLocations, new Comparator<ItemOrderLocation>() {
@Override
public int compare(ItemOrderLocation item1, ItemOrderLocation item2) {
int rowCmp = item1.row.compareTo(item2.row);
int heightCmp = item1.height.compareTo(item2.height);
int posCmp = item1.pos.compareTo(item2.pos);
int item1Row = Integer.parseInt(item1.row);
int item2Row = Integer.parseInt(item2.row);
boolean onForkLiftPath = false;
if (item1Row == (item2Row + 1) && (item2Row % 2 == 0)) {
onForkLiftPath = true;
}
if (!onForkLiftPath && rowCmp != 0) {
//Two differents rows which are not on Fork Lift Path
return rowCmp;
}
//If are on forklift path we compare the position
if (posCmp != 0) {
return posCmp;
}
//Lastly if row is on forklift path and we are on same position we need to sort by nearest height
return heightCmp;
}
});
使用此代码,列表的排序方式如下:
30 02 01
31 07 04
31 02 05
31 03 05
30 04 05
31 07 05
30 09 05
31 09 05
31 03 06
为了更好地理解最终排序列表(最近行程较少的高度)应该如下所示:
30 02 01
31 07 04
31 07 05
30 09 05
31 09 05
30 04 05
31 03 05
31 02 05
31 03 06
任何想法如何使用我的排序算法达到此结果?
答案 0 :(得分:1)
考虑到约束,以下解决了叉车问题。
ALGORITHM
Input: All locations
Output: Shortest path given constraints
1. For all row/pairs, in increasing order
2. For all positions in that row, in increasing order
3. For all heights with same row/pair and position, add locations to minimize the height change given a starting height
代码使用Java 8流。该代码试图使用单一用途的方法;所以请随意用更熟悉的语法重写任何方法。它不能保证优化,但考虑到输入的小尺寸,这不应该是一个问题。如果您有任何问题,请告诉我。
代码:
public class ForkLiftOperator {
public static void main(String[] args) {
new ForkLiftOperator().start();
}
private void start() {
List<Location> locations = new ArrayList<Location>();
locations.add(new Location(30, 9, 5));
locations.add(new Location(30, 4, 5));
locations.add(new Location(30, 2, 1));
locations.add(new Location(31, 7, 5));
locations.add(new Location(31, 7, 4));
locations.add(new Location(31, 3, 5));
locations.add(new Location(31, 3, 6));
locations.add(new Location(31, 9, 5));
locations.add(new Location(31, 2, 5));
locations.add(new Location(32, 2, 5)); // Extra to simulate additional row/pair
List<Location> solution = solve(locations);
System.out.println(solution);
}
private List<Location> solve(List<Location> locations) {
List<Location> shortestPath = new ArrayList<Location>();
int activeRow, activePosition, activeHeight;
while ((activeRow = getNextRow(locations)) != 0) {
System.out.println("Working on row="+activeRow);
List<Location> activeLocations = getLocationsByRowPair(activeRow, locations);
activePosition = 0;
activeHeight = 0;
while ((activePosition = getNextPos(activePosition, activeLocations)) != 0) {
System.out.println("Working on pos="+activePosition);
List<Location> activePositionLocations = getLocationsForRowAndPosition(activeRow, activePosition, activeLocations);
shortestPath.addAll(minimizeHeight(activeHeight, activePositionLocations));
activeHeight = shortestPath.get(shortestPath.size()-1).height;
}
}
return shortestPath;
}
enum Direction { UP, DOWN }
/**
* For the given locations (which are guaranteed to be at the same row/position), minimize the total height change
* @param activePositionLocations The locations at this row/pair and location (they will only differ in height)
* @return The order will minimize the height change
*/
private List<Location> minimizeHeight(int currentHeight, List<Location> activePositionLocations) {
List<Location> optimizedHeightLocations = new ArrayList<Location>();
System.out.println("Processing locations="+activePositionLocations);
int minHeight = activePositionLocations.stream().mapToInt(location -> location.height).min().getAsInt();
int maxHeight = activePositionLocations.stream().mapToInt(location -> location.height).max().getAsInt();
/*
* There are only two options to minimize (if the current height falls between min and max):
* 1) Travel down then up
* 2) Travel up then down
*/
// First determine the first direction to go
Direction direction;
if (currentHeight == minHeight)
direction = Direction.UP;
else if (currentHeight == maxHeight)
direction = Direction.DOWN;
else {
int distanceUp = maxHeight-currentHeight;
int distanceDown = currentHeight-minHeight;
direction = distanceUp < distanceDown ? Direction.UP : Direction.DOWN;
}
// Now travel in that direction (must sort the correct way first
List<Location> sortedAscending = activePositionLocations.stream().sorted((l1, l2) -> Integer.compare(l1.height, l2.height)).collect(Collectors.toList());
List<Location> sortedDescending = activePositionLocations.stream().sorted((l1, l2) -> Integer.compare(l2.height, l1.height)).collect(Collectors.toList());
if (direction == Direction.UP) {
optimizedHeightLocations.addAll(sortedAscending.stream().filter(location -> location.height >= currentHeight).collect(Collectors.toList()));
optimizedHeightLocations.addAll(sortedDescending.stream().filter(location -> location.height < currentHeight).collect(Collectors.toList()));
} else { // Direction = DOWN
optimizedHeightLocations.addAll(sortedDescending.stream().filter(location -> location.height <= currentHeight).collect(Collectors.toList()));
optimizedHeightLocations.addAll(sortedAscending.stream().filter(location -> location.height > currentHeight).collect(Collectors.toList()));
}
return optimizedHeightLocations;
}
/**
* Determine all the locations for this current row/pair and position
* @param activeRow The current row/pair
* @param activePos The current position
* @param locations The locations for this row/pair
* @return The locations at this exact row/pair and position
*/
private List<Location> getLocationsForRowAndPosition(int activeRow, int activePos,
List<Location> locations) {
int minRow = activeRow;
int maxRow = ((activeRow & 1) == 0) ? activeRow + 1 : activeRow; // If even, then pair includes the next higher row
return locations.stream().filter(location -> location.row >= minRow && location.row <= maxRow && location.position == activePos)
.collect(Collectors.toList());
}
/**
* Determine the next position, given the current position
* @param currentPosition Where the operator is currently
* @param locations The locations for this row/pair
* @return The next closest, or zero if they are at the end
*/
private int getNextPos(int currentPosition, List<Location> locations) {
if (locations.isEmpty())
return 0;
OptionalInt min = locations.stream().filter(location -> location.position > currentPosition)
.mapToInt(location -> location.position)
.min();
return min.isPresent() ? min.getAsInt() : 0;
}
/**
* Filter out any locations for this row pair.
* The locations for this row will be removed from the original list
* @param nextRow The current row being processed
* @param locations The remaining locations
* @return The locations for the active row
*/
private List<Location> getLocationsByRowPair(int nextRow, List<Location> locations) {
List<Location> activeLocations = new ArrayList<Location>();
Iterator<Location> i = locations.iterator();
int minRow = nextRow;
int maxRow = ((nextRow & 1) == 0) ? nextRow + 1 : nextRow; // If even, then pair includes the next higher row
while (i.hasNext()) {
Location current = i.next();
if (current.row >= minRow && current.row <= maxRow) {
activeLocations.add(current);
i.remove();
}
}
return activeLocations;
}
/**
* Determine the lowest row from the locations provided
* @param locations All remaining locations
* @return The minimum row number remaining
*/
private int getNextRow(List<Location> locations) {
if (locations.isEmpty())
return 0;
return locations.stream().mapToInt(location -> location.row)
.min().getAsInt();
}
class Location {
final int row;
final int position;
final int height;
public Location(int row, int height, int position) {
this.row = row;
this.position = position;
this.height = height;
}
@Override
public String toString() {
return "[" + row + ", " + height + ", " + position + "]";
}
}
}
生成以下输出,该输出与所需的输出匹配:
[[30,2,1],[31,7,4],[31,7,5],[30,9,5],[31,9,5],[30,4,5] ],[31,3,5],[31,2,5],[31,3,6],[32,2,5]]
以下是当前Java8代码的Java7版本:
Java8:
private List<Location> getLocationsForRowAndPosition(int activeRow, int activePos,
List<Location> locations) {
int minRow = activeRow;
int maxRow = ((activeRow & 1) == 0) ? activeRow + 1 : activeRow; // If even, then pair includes the next higher row
return locations.stream().filter(location -> location.row >= minRow && location.row <= maxRow && location.position == activePos)
.collect(Collectors.toList());
}
Java 7:
private List<Location> getLocationsForRowAndPosition(int activeRow, int activePos,
List<Location> locations) {
int minRow = activeRow;
int maxRow = ((activeRow & 1) == 0) ? activeRow + 1 : activeRow; // If even, then pair includes the next higher row
List<Location> positionLocations = new ArrayList<Location>();
for (Location location : locations) {
if (location.row >= minRow && location.row <= maxRow && location.position == activePos)
positionLocations.add(location);
}
return positionLocations;
}
Java 8:
private int getNextPos(int currentPosition, List<Location> locations) {
if (locations.isEmpty())
return 0;
OptionalInt min = locations.stream().filter(location -> location.position > currentPosition)
.mapToInt(location -> location.position)
.min();
return min.isPresent() ? min.getAsInt() : 0;
}
Java 7:
private int getNextPos(int currentPosition, List<Location> locations) {
if (locations.isEmpty())
return 0;
int minValue = Integer.MAX_VALUE;
for (Location location : locations) {
if (location.position > currentPosition && location.position < minValue)
minValue = location.position;
}
return minValue == Integer.MAX_VALUE ? 0 : minValue;
}
Java 8:
private int getNextRow(List<Location> locations) {
if (locations.isEmpty())
return 0;
return locations.stream().mapToInt(location -> location.row)
.min().getAsInt();
}
Java 7:
private int getNextRow(List<Location> locations) {
if (locations.isEmpty())
return 0;
int minValue = Integer.MAX_VALUE;
for (Location location : locations) {
if (location.row < minValue)
minValue = location.row;
}
return minValue;
}
最后使用Java 7 for minimizeHeight:
private List<Location> minimizeHeight(int currentHeight, List<Location> activePositionLocations) {
List<Location> optimizedHeightLocations = new ArrayList<Location>();
int minHeight = Integer.MAX_VALUE;
int maxHeight = Integer.MIN_VALUE;
for (Location location : activePositionLocations) {
if (location.height < minHeight)
minHeight = location.height;
if (location.height > maxHeight)
maxHeight = location.height;
}
/*
* There are only two options to minimize (if the current height falls between min and max):
* 1) Travel down then up
* 2) Travel up then down
*/
// First determine the first direction to go
Direction direction;
if (currentHeight == minHeight)
direction = Direction.UP;
else if (currentHeight == maxHeight)
direction = Direction.DOWN;
else {
int distanceUp = maxHeight-currentHeight;
int distanceDown = currentHeight-minHeight;
direction = distanceUp < distanceDown ? Direction.UP : Direction.DOWN;
}
// Now travel in that direction (must sort the correct way first
List<Location> sortedAscending = new ArrayList<Location>(activePositionLocations); // Clone it
Collections.sort(sortedAscending, new Comparator<Location>() {
@Override
public int compare(Location l1, Location l2) {
return Integer.compare(l1.height, l2.height);
}
});
List<Location> sortedDescending = new ArrayList<Location>(activePositionLocations); // Clone it
Collections.sort(sortedDescending, new Comparator<Location>() {
@Override
public int compare(Location l1, Location l2) {
return Integer.compare(l2.height, l1.height);
}
});
if (direction == Direction.UP) {
for (Location location : sortedAscending) {
if (location.height >= currentHeight)
optimizedHeightLocations.add(location);
}
for (Location location : sortedDescending) {
if (location.height < currentHeight)
optimizedHeightLocations.add(location);
}
} else { // Direction = DOWN
for (Location location : sortedDescending) {
if (location.height <= currentHeight)
optimizedHeightLocations.add(location);
}
for (Location location : sortedAscending) {
if (location.height > currentHeight)
optimizedHeightLocations.add(location);
}
}
return optimizedHeightLocations;
}