【问题标题】:Assigning soldiers to a room algorithm issue将士兵分配到房间算法问题
【发布时间】:2016-03-14 15:20:25
【问题描述】:

所以我有一个搜索问题需要在 Java 中进行优化。这是一个示例,说明了我要解决的问题。

一名士兵到达一个基地并被分配到一个住房单元。每个基地都有一个或多个住房单元。

每个住房单元都有一个或多个房间。每个房间里都有多张床。每个房间都有一个优先级编号(1 是最高优先级)。每个房间的床位数可以不同。

士兵需要分配到一个房间。他被分配到拥有最多可用床位的房间。如果有多个房间的床位数相同,他会去优先级更高的房间。

一旦士兵被分配到一个房间,可用床位的数量当然会更新,并且队列中的下一个士兵将使用相同的过程添加,直到所有士兵都被分配到房间。

如果无法将士兵分配到床位,我们不必担心,因为没有可用的床位。另一个进程负责处理这种溢出情况。

我的问题是哪种 Java 数据结构实现最能解决士兵将被分配到哪个房间的问题?

目前我用的是多维ArrayList,感觉一定有更好的办法。

【问题讨论】:

  • 向我们展示你到目前为止所做的尝试
  • 这是我目前关于如何解决问题的思考过程:1)拥有一系列住房单元。在数组中找到住房单元,O(n)。 2) 每个住房单元都有一系列房间。搜索房间以找到可用床最多且优先级最高的房间,O(n)。我的解决方案是 O(n) 的大 O 表示法。虽然这是可以接受的,但我觉得我应该能够以某种方式使用树获得更快的解决方案?我只是对实现这样的树或其他解决方案有点不知所措。
  • 我不认为有任何单一的数据结构可以使用。但是,如果您想制作大部分现有集合(这不一定是最优雅的解决方案),您可以在基本级别尝试 Map (因为您预先获得了住房单元分配,所以只需要查找)和 PriorityQueue在住房层。然后,根据床位*1000+(1000-priority) 使 Room 具有可比性(1000 是保证大于最大优先级的某个数字)。然后,当你分配时,从队列中提取最高优先级,更新,放回去。您可以使用辅助地图 进行其他查找。

标签: java search data-structures


【解决方案1】:

在设计和时间复杂度方面,您当然可以做得比多维 ArrayList 更好。

从设计的角度来看,您有三个包含类 - RoomHouseBase。 (也可以是Soldier,尽管出于我们的目的,Soldier 不需要任何额外信息。)

public class Soldier{}

首先,Room 相当简单。它必须包含Soldiers 并知道它还剩下多少个开放房间

public class Room {

    private int totalBeds;
    public final int priority;
    private ArrayList<Soldier> soldiers;

    public Room(int totalBeds, int priority) {
        this.totalBeds = totalBeds;
        this.priority = priority;
        soldiers = new ArrayList<>();
    }

    public boolean add(Solider s) {
        if(soldiers.size() >= totalBeds) {
            return false;
        }
        return soldiers.add(s);
    }

    public int getRemainingBeds() {
        return totalBeds - soldiers.size();
    }

    public boolean isFull() {
        return totalBeds <= soldiers.size();
    }
}

从那里,我们需要一个House 类。这是Rooms 的优先级队列,必须能够根据其优先级将士兵添加到房间。

public class House {

    private final String name;
    private PriorityQueue<Room> rooms;

    public House(String name, Room... rooms) {
        this.name = name;
        this.rooms = new PriorityQueue<>(new Comparator<Room>() {
            public int compare(Room a, Room b) {

                //Always prioritize an open room to a full one
                if(a.isFull() && b.isFull()) {
                    return 0;
                } else if (a.isFull()) {
                    return 1;
                } else if (b.isFull()) {
                    return -1;
                } else {
                    //Now try to get the room with the most available rooms
                    int bedDiff = b.getRemainingBeds() - a.getRemainingBeds();
                    if(bedDiff != 0) {
                        return bedDiff;
                    }
                    return a.priority - b.priority;
                }
           }
       });
       for(Room r : rooms) {
           this.rooms.add(r)
       }
    }

    public boolean add(Soldier s) {
        Room r = rooms.poll();
        boolean ok = r.add(s);
        rooms.add(r);
        return ok;
    }

    public String getName() {
        return name;
    }
}

最后,Base 类应该使用Map&lt;String, House&gt; 来通过名称快速定位房子

public class Base {

    private Map<String, House> houses;

    public Base(House... houses) {
        houses = new HashMap<>();
        for(House h : houses) {
            houses.put(h.getName(), h);
        }
    }

    public boolean add(String houseName, Soldier s) {
        return houses.get(houseName).add(s);
    }
}

将士兵添加到基地的全时复杂度:

- Finding the correct House: O(1)
- Adding to the House:
    - Poll: O(log(#rooms in house))
    - Add to room: O(1)
    - Add: O(log(#rooms in house))

【讨论】:

  • 哇,这个解决方案又快又简单!我将尝试为我的问题实施此解决方案。我有同事认为他可以用一棵树做到这一点,但我不确定它会比你拥有的更好。无论哪种方式,我都会在接下来的一两天内发布我的最终解决方案并选择最佳解决方案。
  • 因此,在与业务分析师交谈后,我的业务需求最终发生了变化(这从未发生过,哈哈哈/s),因此我将无法发布与我的问题相匹配的代码。我将使用其中的一些编码逻辑来帮助解决我的新需求。非常感谢您的帮助!
【解决方案2】:

这里有一个建议:

  1. 首先,您不必担心“住房单元”,因为它永远不会进入决策过程的方程式。
  2. 或许可以创建一个Room 类来保存名称/住房单元(例如“A1”)、可用床位数量和优先级的字段。
  3. 创建一个包含Room[] rooms(或等效项)的数组,并按照接下来要带士兵的位置对其进行排序(#beds 和优先级)。
  4. 当一名士兵进来时,他在rooms[0] 中取一张床,移走一张床。如果房间现在已满,请将其从列表中删除。
  5. 然后取rooms[0] 并通过与它下面的rooms[i] 比较找到它的新索引,直到找到新索引。

继续此操作,直到 rooms 为空

【讨论】:

    【解决方案3】:

    听起来您可以使用 PriorityQueue 并为 Room 类使用自定义比较器:

    PriorityQueue<Room> queue = new PriorityQueue<>(new Comparator<Room>() {
      @Override
      public int compare(Room a, Room b) {
        int compareByAvailableBeds = Integer.compare(
            b.getAvailableBeds(), a.getAvailableBeds());
        if (compareByAvailableBeds != 0) {
          return compareByAvailableBeds;
        }
    
        return Integer.compare(a.getPriority(), b.getPriority());
      }
    });
    

    现在,要将士兵分配到房间,您可以采用“最低”优先级Room,将其从队列中删除,将其分配给士兵,然后将其重新添加到队列中:

    Room room = queue.poll();
    room.assign(soldier);  // Assuming this decrements the number of available beds.
    queue.add(room);
    

    【讨论】:

    • 我什至不知道 java 有一个优先队列!很棒的建议。我将研究一下 Java 的 PriorityQueue
    猜你喜欢
    • 1970-01-01
    • 2021-01-30
    • 1970-01-01
    • 2013-07-17
    • 2020-12-02
    • 2020-08-14
    • 2013-07-23
    • 2011-07-19
    • 1970-01-01
    相关资源
    最近更新 更多