Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 按姓氏把人分成几个房间?_Algorithm - Fatal编程技术网

Algorithm 按姓氏把人分成几个房间?

Algorithm 按姓氏把人分成几个房间?,algorithm,Algorithm,我经常教大型的编程入门课程(400-600名学生),当考试时间到来时,我们常常不得不将课程分成不同的教室,以确保每个人都有座位参加考试 为了保持逻辑上的简单,我通常按姓氏将类分开。例如,我可能会把姓A-H的学生送到一个房间,姓I-L的学生送到第二个房间,姓M-S的学生送到第三个房间,姓T-Z的学生送到第四个房间 这样做的挑战是,教室的容量往往相差悬殊,很难找到一种方法来划分班级,使每个人都能适应。例如,为简单起见,假设姓氏的分布如下: 姓氏以A:25开头 姓氏以B:150开头 姓氏以C:200

我经常教大型的编程入门课程(400-600名学生),当考试时间到来时,我们常常不得不将课程分成不同的教室,以确保每个人都有座位参加考试

为了保持逻辑上的简单,我通常按姓氏将类分开。例如,我可能会把姓A-H的学生送到一个房间,姓I-L的学生送到第二个房间,姓M-S的学生送到第三个房间,姓T-Z的学生送到第四个房间

这样做的挑战是,教室的容量往往相差悬殊,很难找到一种方法来划分班级,使每个人都能适应。例如,为简单起见,假设姓氏的分布如下:

  • 姓氏以A:25开头
  • 姓氏以B:150开头
  • 姓氏以C:200开头
  • 姓氏以D:50开头
假设我有容量为350、50和50的房间。查找房间分配的贪婪算法可能是将房间按容量降序排序,然后尝试按该顺序填充房间。不幸的是,这并不总是有效的。例如,在这种情况下,正确的选择是将姓氏A放在一个50号房间,姓氏B-C放在350号房间,姓氏D放在另一个50号房间。贪婪算法会将姓氏A和B放入350人的房间,然后无法为其他人找到座位

通过尝试房间排序的所有可能排列,然后对每个排序运行贪婪算法,很容易解决这个问题。这将查找有效的分配或报告不存在分配。然而,考虑到房间数量可能在10到20之间,并且检查所有排列可能不可行,我想知道是否有更有效的方法来做到这一点

总而言之,正式的问题陈述如下:

你会得到一个班级学生姓氏的频率直方图,以及一个房间及其容量的列表。你的目标是按照学生姓氏的第一个字母将他们分开,这样每个房间都会被分配一个连续的字母块,并且不会超过其容量

是否有一种有效的算法,或者至少有一种算法对合理的房间大小有效

编辑:许多人都询问过相邻条件。规则是

  • 每个房间最多应分配一块连续的字母,以及
  • 不得将任何信件分配给两个或多个房间
例如,不能将A-E、H-N和p-Z放在同一个房间中。你也不能把A-C放在一个房间,B-D放在另一个房间


谢谢

这个问题是
NP完全的
,因此没有已知的
多项式
时间(也称有效)解决方案(只要人们不能证明
p=NP
)。您可以将背包或箱子包装问题的实例简化为您的问题,以证明它是
NP完全的

要解决这个问题,你可以使用0-1背包问题。以下是如何: 首先选择最大的教室大小,并尝试分配尽可能多的学生组(使用0-1个背包),即与房间大小相等。你保证不会分裂一组学生,因为这是0-1背包。完成后,到下一个最大的教室继续上课

(您可以使用任何已知的启发式方法来解决0-1背包问题。)

这是降价单-- 您需要将0-1背包的一般实例简化为问题的特定实例。 让我们来举一个0-1背包的一般例子。让我们拿一个重量为
W
的袋子,你有
x_1,x_2。。。x_n
组及其相应的权重为
w_1,w_2。。。w_n

现在简化——这个一般实例简化为您的问题,如下所示: 您有一间可容纳座位的教室
W
。每个
x_i(i\in(1,n))
是一组学生,他们的最后一个字母表以
i
开头,他们的数字(也称为组大小)是
w_i

现在你可以证明,如果0-1背包问题有解,你的问题有解……反之亦然……如果0-1背包没有解,那么你的问题就没有解,反之亦然


请记住简化的重要内容——将已知
NP-C
问题的一般实例简化为您的问题的特定实例


希望这有帮助:)

可以在
[m,2^n]
空间中使用某种DP解决方案来解决,其中
m
是字母数(英文为26),而
n
是房间数。使用
m==26
n==20
将需要大约100MB的空间和约1秒的时间。 下面是我刚在C语言中实现的解决方案(它将成功地在C++和java上编译,只需要几个小的改动):

int[]GetAssignments(int[]studentsPerLetter,int[]rooms)
{
int numberOfRooms=房间长度;
int numberOfLetters=studentsPerLetter.Length;
int roomset=1=0&&roomCapacity>=studentsPerLetter[lastIndex];lastIndex--)
{
res[lastIndex]=lastRoom;
房间容量-=学生人数[lastIndex];
}
roomMask^=1-1?空值:res;
}
OP问题示例:

答案是:

2
0
0
1
表示每个学生姓氏字母的房间索引。如果无法分配,我的解决方案将返回
null


[编辑]

在数千次自动生成的测试之后,我的朋友发现代码中有一个错误,它会反向构造解决方案。它不会影响主算法,因此修复此错误将是读者的一项练习

揭示错误的测试用例是
students=[
2
0
0
1