这是关键:
实际上,一名船员连续7天无法工作.每7天一次,必须有1天休息.
将问题改为每7天随机说2天(或将月份分成四段时间).然后,您将获得均匀分布.使用random.sample()作为Martijn Pieters建议.
您可以从第一周开始使用此技术生成两个值,然后按顺序生成它们,如果您需要逐个生成它们.
编辑:
正如tcaswell所观察到的,仍有一些情况下你最终连续十天值班.要解决这个问题,您可以每三天分配一天,创建十个列表,并从不影响7连续日标准的天数子集中随机删除两天.
或者,您可以使用原始算法生成列表,直到符合条件,因为您很可能无论如何都会获得有效的解决方案.你必须编写某种验证函数,但这样做很容易,因为你只计算最长的连续日期.
码:
第二种选择的实现.
import random
from itertools import chain
from itertools import count
def candidate(m):
''' Returns 2 days per week, in m days, where m is the length of the month. '''
weeks = weeksmaker(m)
return sorted(list(chain(*[random.sample(week, 2) for week in weeks])))
def weeksmaker(m):
''' Divides a month up into four weeks, randomly assigning extra days to weeks. '''
weeks = [range(i, i+7) for i in xrange(1,29,7)]
for i in range(m - 28):
weeks[random.randint(1, len(weeks))-1].append(i)
c = count(1)
return [[c.next() for day in week] for week in weeks]
def valid(days, c):
''' Validity check. Cant work more than c consecutive days. '''
for i in xrange(1, len(days)):
if days[i] - days[i-1] > c:
return False
else:
return True
def daysoff(m, n, c):
''' In month length m, need n days off, cant work more than c consecutive days. '''
while True:
days = candidate(n)
if valid(days, c):
return days
>>> for i in range(28, 32):
... daysoff(i, 8, 7)
...
[6, 7, 10, 14, 18, 20, 27, 28]
[4, 7, 10, 13, 19, 21, 23, 24]
[2, 4, 9, 13, 15, 20, 25, 27]
[1, 3, 9, 12, 18, 19, 24, 28]