用于有效分配项目和满足最小值的已知算法?

时间:2011-11-03 17:04:44

标签: algorithm sorting language-agnostic

对于以下问题,我想知道是否已经存在已知算法,因为我不想重新发明轮子。

在这种情况下,这是关于酒店房间,但我认为这是无关紧要的:

name   | max guests | min guests
1p     | 1          | 1
2p     | 2          | 2
3p     | 3          | 2
4p     | 4          | 3

我正在尝试在可用房间分配一定数量的客人,但分配必须满足房间的“最小客人”标准。此外,房间需要尽可能高效地使用。

我们以7位客人为例。我不想要这个组合:

3 x 3p ( 1 x 3 guests, 2 x 2 guests )

..这将满足最低标准,但效率低下。相反,我正在寻找组合,如:

1 x 3p and 1 x 4p
3 x 2p and 1 x 1p
etc...

我认为这是一个熟悉的问题。有没有已知的算法来解决这个问题?

澄清:
我的意思是,通过高效的方式分配客人,使房间尽可能地被填满(客人的偏好在这里是次要问题,对我正在寻找的算法并不重要)。 我希望所有符合此效率标准的排列。所以在上面的示例7 x 1p也可以。

总结如下:
是否有一种已知的算法能够在minmax容量,始终满足 min条件的<= 1>的广告位上尽可能高效地分配项目强>尝试尽可能满足 max标准。

5 个答案:

答案 0 :(得分:1)

您需要使用dynamic programming,定义成本函数,并尝试让人们适应具有尽可能小的成本函数的可能房间。

您的费用函数可以是:

房间空缺总数+房间数


它可能有点类似于最小的愤怒问题:Word wrap to X lines instead of maximum width (Least raggedness)

你适合在房间里的人,因为你排成一行。

限制是房间的空位而不是线的长度。 (如果不满足约束,则无限成本)

和递归关系几乎相同。

希望有所帮助

答案 1 :(得分:0)

对于efficint =使用的最小房间,也许这会起作用。为了最大限度地减少您想要将max guests放入大房间的房间数量。

按照max guests的降序对房间进行排序,然后按顺序将客人分配给他们,依次将max guests放在每个房间。尝试将所有剩余的客人放置在可以接受许多min guests的剩余房间内;如果这是不可能的,回溯并重试。回溯时,请按住最小min guests的房间。在max guests阶段,未分配的客房未分配给客人。


修改

正如Ricky Bobby指出的那样,由于后向跟踪的困难,这不起作用。我现在保留这个答案,更多的是作为警告而不是建议: - )

答案 2 :(得分:0)

$sql = "SELECT * 
FROM rooms 
WHERE min_guests <= [$num_of_guests]
ORDER BY max_guests DESC
LIMIT [$num_of_guests]";

$query = $this->db->query($sql);
$remaining_guests = $num_of_guests;
$rooms = array();
$filled= false;
foreach($query->result() as $row)
{
 if(!$filled)
 {
  $rooms[] = $row;
  $remaining_guests -= $row->max_guests;
  if(remaining_guests <= 0)
  {
   $filled = true;
   break;
  }
 }
}

递归函数:

public function getRoomsForNumberOfGuests($number)
{
  $sql = "SELECT * 
  FROM rooms 
  WHERE min_guests <= $number
  ORDER BY max_guests DESC
  LIMIT 1";

  $query = $this->db->query($sql);
  $remaining_guests = $number;
  $rooms = array();
  foreach($query->result() as $row)
  {
    $rooms[] = $row;
    $remaining_guests -= $row->max_guests;
    if($remaining_guests > 0)
    {
     $rooms = array_merge($this->getRoomsForNumberOfGuests($remaining_guests), $rooms);
    }
  }
  return $rooms;
}

这样的事情对你有用吗?不确定你的语言是什么?

答案 3 :(得分:0)

这可以作为对递归算法的相当简单的修改来枚举整数分区来完成。在Python中:

import collections

RoomType = collections.namedtuple("RoomType", ("name", "max_guests", "min_guests"))


def room_combinations(count, room_types, partial_combo=()):
    if count == 0:
        yield partial_combo
    elif room_types and count > 0:
        room = room_types[0]
        for guests in range(room.min_guests, room.max_guests + 1):
            yield from room_combinations(
                count - guests, room_types, partial_combo + ((room.name, guests),)
            )
        yield from room_combinations(count, room_types[1:], partial_combo)


for combo in room_combinations(
    7,
    [
        RoomType("1p", 1, 1),
        RoomType("2p", 2, 2),
        RoomType("3p", 3, 2),
        RoomType("4p", 4, 3),
    ],
):
    print(combo)

答案 4 :(得分:0)

  1. 我们应该选择一个房间列表(每个房间可能不止一次),以使所选房间的最小值总和等于或小于客人人数和最大值的总和等于或大于客人人数。

  2. 我将成本定义为所选房间的总可用空间。 (费用=最高-最低)

  3. 我们可以使用此代码检查答案,并以最低的成本找到所有可能的组合。 (C#代码)

    class FindRooms
    {
        // input
        int numberOfGuest = 7; // your goal
        List<Room> rooms;

        // output
        int cost = -1; // total free space in rooms. 
        List<String> options; // list of possible combinations for the best cost

        private void solve()
        {
            // fill rooms data
            // fill numberOfGuest
            // run this function to find the answer
            addMoreRoom("", 0, 0);
            // cost and options are ready to use
        }

        // this function add room to the list recursively

        private void addMoreRoom(String selectedRooms, int minPerson, int maxPerson)
        {
            // check is it acceptable
            if (minPerson <= numberOfGuest && maxPerson >= numberOfGuest)
            {
                // check is it better than or equal to previous result
                if(maxPerson - minPerson == cost)
                {
                    options.Add(selectedRooms);
                }
                else if (maxPerson - minPerson < cost)
                {
                    cost = maxPerson - minPerson;
                    options.Clear();
                    options.Add(selectedRooms);
                }
            }

            // check if too many room selected
            if (minPerson > numberOfGuest)
                return;

            // add more room recursively
            foreach (Room room in rooms)
            {
                // add room and min and max space to current state and check
                addMoreRoom(selectedRooms + "," + room, minPerson + room.min, maxPerson + room.max);
            }
        }
        public class Room
        {
            public String name;
            public int min;
            public int max;
        }
    }