我遇到了这个问题,我不确定我的解决方案是否是最优的。
给定N加权(Wi)和可能重叠的间隔(代表会议日程),找到最小数量"&"会议室开展所有会议所需的能力。
|---10------|. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|---------8---------|
|------8-----| |----------10-----------|
|--------6-------|
对于上述时间表,我们需要两个10和10个容量的会议室。 (我是对的吗?)
如果我们有一个容量大于所需容量的会议室使用它,如果没有符合标准的会议室,建立一个新的房间或增加现有的房间,请从一个房间,并从左侧移动间隔有新容量的房间。
示例:
10开始 - {10}
8开始 - {10,8}
10月底 - {10-free,8}
6的开始 - {10,8}
8结束 - {10,8-free}
10的开始= {10,8 + = 2}或{10,10}
依旧.....
这基本上是贪婪的..
答案 0 :(得分:6)
我认为这个问题相当于“铁路/公交车站所需的最低平台数”问题。
本文http://www.geeksforgeeks.org/minimum-number-platforms-required-railwaybus-station/解释了如何处理它。
答案 1 :(得分:4)
我会试一试。天真的方法是列举所有可能的解决方案并选择最好的解决方案。考虑到这一点,找到可以容纳k
次会议的n
个会议室等同于找到k
分段的n
点。 OP示例中2
会议的5
分区方式示例为[ 0,2,4 ]
和[ 1,3 ]
:
|---0------| |---------4---------|
|------1-----| |----------3-----------|
|--------2-------|
因此,基本思想是枚举k
个会议的所有n
- 路分区,其约束条件是两个重叠的会议不能属于同一个群集。例如,[ 0,1,2 ]
和[ 3,4 ]
不是有效分区,因为会议[ 0,1,2 ]
无法在会议室中进行;会议同样适用[ 3,4 ]
。幸运的是,使用递归方法时,约束很容易实现。
使用Python
,它看起来像这样:
def kWay( A, k, overlap ) :
"""
A = list of meeting IDs, k = number of rooms,
overlap[ meeting ID m ] = set of meetings overlapping with m
"""
if k == 1 : # only 1 room: all meetings go there
yield [ A[:] ]
elif k == len(A) : # n rooms and n meetings: put 1 meeting per room
yield [ [a] for a in A ]
else :
for partition in kWay( A[1:], k, overlap ) : # add new meeting to one existing room
for i, ci in enumerate( partition ) :
isCompatible = all( A[0] not in overlap[x] for x in ci ) # avoid 2 overlapping meetings in the same room
res = partition[:i] + [ ci + [ A[0] ] ] + partition[ i+1: ]
if isCompatible :
yield res
for partition in kWay( A[1:], k-1, overlap ) : # add new meeting to a new room
isValid = ( set(A[1:]) & set.union( * ( overlap[a] for a in A[ 1: ] ) ) == set() ) # avoid 2 overlapping meetings in the same room
if (k-1>1) or ( k-1==1 and isValid ) :
yield partition + [ [ A[0] ] ]
这看起来有点复杂但实际上很简单,当你意识到它只是k
方式分区+ 2个额外行的递归算法,以保证我们只考虑有效分区。
好的,现在让我们使用OP示例准备输入数据:
import collections
n = 5
k = 2
#
A = range(n)
# prepare overlap dictionary
pairs = [ (0,1), (1,2), (2,3), (3,4) ] # overlapping meetings
size = dict( ( (0,10), (1,8), (2,6) , (3,10), (4,8) ) )
overlap = collections.defaultdict(set)
for (i,j) in pairs :
overlap[i].add(j)
overlap[j].add(i)
defaultdict(<type 'set'>, {0: set([1]), 1: set([0, 2]), 2: set([1, 3]), 3: set([2, 4]), 4: set([3])})
{0: 10, 1: 8, 2: 6, 3: 10, 4: 8}
现在我们只是遍历有效的2
路分区并打印房间大小。只有一个有效的分区,所以这是我们的解决方案:
for partition in kWay( A, k, overlap ) :
print partition, [ max( size[x] for x in c ) for c in partition ]
[[3, 1], [4, 2, 0]] [10, 10]
好的,所以会议1,3
会占用10
个会议室,会议0,2,4
会进入10
的会议室。
但是只有一个有效的2
- 路分区,所以当然这也是最佳解决方案。多么无聊!让我们为OP示例添加一个新会议5
和一个新会议室,以使其更有趣:
|---0------| |---5---| |---------4---------|
|------1-----| |----------3-----------|
|--------2-------|
对应的输入数据:
n = 6
k = 3
#
A = range(n)
pairs = [ (0,1), (1,2), (2,3), (3,4), (5,2), (5,3) ] # overlapping meetings
size = dict( ( (0,10), (1,8), (2,6) , (3,10), (4,8), (5,2) ) )
overlap = collections.defaultdict(set)
for (i,j) in pairs :
overlap[i].add(j)
overlap[j].add(i)
defaultdict(<type 'set'>, {0: set([1]), 1: set([0, 2]), 2: set([1, 3, 5]), 3: set([2, 4, 5]), 4: set([3]), 5: set([2, 3])})
{0: 10, 1: 8, 2: 6, 3: 10, 4: 8, 5: 2}
结果:
for partition in kWay( A, k, overlap ) :
print partition, [ max( size[x] for x in c ) for c in partition ]
[[3, 1], [4, 2, 0], [5]] [10, 10, 2]
[[3, 1], [4, 2], [5, 0]] [10, 8, 10]
[[3, 0], [4, 2], [5, 1]] [10, 8, 8]
[[3], [4, 2, 0], [5, 1]] [10, 10, 8]
[[4, 5, 1], [3, 0], [2]] [8, 10, 6]
[[4, 5, 1], [3], [2, 0]] [8, 10, 10]
[[4, 5, 0], [3, 1], [2]] [10, 10, 6]
[[4, 5], [3, 1], [2, 0]] [8, 10, 10]
最佳3
- 方式分区为[[3, 1], [4, 2, 0], [5]]
,最佳房间大小为[10, 10, 2]
。您还可以直接获得所有房间的最小尺寸:
min( sum( [ max( size[x] for x in c ) for c in partition ] ) for partition in kWay( A, k, overlap ) )
22
答案 2 :(得分:1)
考虑这种情况:
(m1) |-3-|
(m2) |--2--|
(m3) |--1--|
(m4) |-1-|
(m5) |-2-|
您的解决方案将继续:
此解决方案的累积容量为8。
现在考虑这个解决方案:{3,2,1,1}。它的累积容量为7 在上面的步骤(4),m4将进入未占用的1个房间,3个房间仍然是打开的。因此,这就是m5将要去的地方。
做出的假设
算法更改
更新:我刚刚意识到,即使进行此更改,创建一个房间仍然可以导致次优解决方案。原因是人们可以在创建新房间之前调整现有房间的大小。
举个例子,假设我们在四个房间里举行了四次会议。
我们寻求添加m5(5号)。我提议的算法更改将创建一个新的5个房间,累积容量增加5。但是,我们可以将m2的房间调整为5个房间,让m5去那里,并为m2建造一个2号房间。这只会增加2个累积容量。
有人可能想知道为什么不将m2放入2个房间之一(取代m3)并创建一个新的1个房间。调整房间大小更加困难,因为我们不能保证在需要它的会议开始时会打开房间。添加房间比较容易,因为那个房间总是在那里;它没有被使用,因为我们刚刚在算法的这一步创建了它。
次优算法更改 如上所述,这被证明是次优的,但我一直在这里,直到我能想到一个更好的选择。
要考虑上述情况,您需要在创建新房间时进行额外的工作:
因此,在上面的示例中,当需要创建新房间时,这种改变在步骤5起作用。上面的步骤说明:
答案 3 :(得分:1)
要查找举行所有会议所需的会议室的最低数量和容量, 您首先需要将这些会议安排到房间(具有最小化房间容量的分数功能)。该调度(类似于course scheduling)是NP完全的或NP难的。这意味着你的问题也是如此。
反过来,这意味着没有已知的算法可以解决您的问题。贪心算法(包括你的例子)不会始终是最优的(或者如果你有更多的约束,甚至不是最优的) - 但至少它们会缩放:)为了获得更好的结果(如果需要),请研究优化算法,例如metaheuristics。
答案 4 :(得分:-1)
{
"id": "GDT Expanded",
"name": "GDT Expanded",
"version": "0.1",
"author": "Steven_Rochfort",
"url": "http://sites.simbla.com/fb3f8974-2f77-9836-04e4-d36177c9da09/Home",
"description": "This mod aims to expand your game by adding topics, researches, events etc. **THIS MOD IS AT AN EARLY STAGE, USE AT YOUR OWN RISK**",
"main": "./source.js",
"dependencies": {
"gdt-modAPI": "0.1.x"
},
"image": "Icons/GDTE.png"
}
答案 5 :(得分:-1)
以下是我的解决方案。
class Meeting{
LocalTime start;
LocalTime end;
Meeting(LocalTime start, LocalTime end){
this.start = start;
this.end = end;
}
}
public static int meeingRoom(List<Meeting> list){
//use queue structure to store the room in use
Queue<Meeting> rooms = new LinkedList<Meeting>();
rooms.add(list.get(0));
for(int i = 1; i< list.size(); i++){
Meeting current = list.get(i);
//max: keep the max of ever occupied
//occupied: so far occupied room
int max = 1, occupied = 1;
List<Meeting> rooms = new ArrayList<Meeting>();
rooms.add(list.get(0));
for(int i = 1; i< list.size(); i++){
Meeting current = list.get(i);
int roomSize = rooms.size();
//check all previous rooms to release finish room
for(int j = 0; j < roomSize; j++){
if(j >= rooms.size()) break;
Meeting previous = rooms.get(j);
if(current.start.compareTo(previous.end) >= 0){
rooms.remove(j);
}
rooms.add(current);
//when all the rooms once occupied, all remove
//reset the occupied
if(rooms.size() == 1 ){
max = Math.max(occupied, max);
occupied = 1;
}else{
occupied = Math.max(occupied, rooms.size());
};
}
//the last time added room hasn't been check
return Math.max(occupied, max);
}