题目
某研究室有四台设备需要以天为单位(周一至周日)安排轮换启用,轮换规则为:
每台设备功能相同
每台设备每周需要启用四天
每台设备之间启用时间不能完全相同
周一至周五每天需要两台设备工作
周六周日每天需要三台设备工作
每种设备需要在周六周日中至少一天工作
试利用编程方式计算:
1)
共有多少种设备排班方案(若日期相同而分配设备不同视作同一方案,例如
[1356, 1467, 2357, 2467]与[1467, 2357, 1356, 2467]视作同一方案)
2)
限定每台设备均不能连续工作超过两天(例如 123、567、671 均不可),重新
计算排班方案数量
分析
1 2 3 4 5 6 7 sum
d1 - - - - - - - 4
d2 - - - - - - - 4
d3 - - - - - - - 4
d4 - - - - - - - 4
sum 2 2 2 2 2 3 3
- 根据题意,可转为上述模型,中间区域一共28个位置,每个位置为0或1,1代表设备启用
因此将问题转换为在28个位置中插入16个1,12个0,即0与1的分配问题 - 每台设备周六日最少启用一天,则可以分为两种情况:
周一至周五启用两天,周六日启用两天
周一至周五启用三天,周六日启用一天
代码实现(python)
代码仅实现功能,未考虑性能,仅供参考
实现:
from itertools import combinations
import numpy as np
# 一台设备一周的排班方案
one_dev_plan = list()
# 周1~5 - 索引
mon_to_fri = [0, 1, 2, 3, 4]
# 周1~5任选两天再加周六周日的组合方案
two_and_two = list(combinations(mon_to_fri, 2))
for plan in two_and_two:
one_dev_plan.append(plan + (5, 6))
# 周1~5任选三天再加周六日中的一天的组合方案
three_and_one = list(combinations(mon_to_fri, 3))
for plan in three_and_one:
one_dev_plan.append(plan + (5,))
one_dev_plan.append(plan + (6,))
# 设备一周的排列情况中选出4种作为四台设备一周的排列情况
four_dev_plan = list(combinations(one_dev_plan, 4))
# result_1 - 第一问结果,list_28 - 28个位置的0、1排列
result_1, list_28 = list(), list()
# 周一至周五每天需要两台设备工作,周六周日每天需要三台设备工作
tar_arr = np.array([2, 2, 2, 2, 2, 3, 3])
# t_indices:((0, 3, 5, 6), (0, 2, 3, 5), (0, 2, 4, 5), (1, 2, 3, 5))
for t_indices in four_dev_plan:
for indices in t_indices:
# 一台设备一周的0、1排列
dev_list = np.zeros(7)
dev_list[list(indices)] = 1
list_28.append(dev_list)
# list_28转换成ndarray数组,便于列相加操作
arr_28 = np.array(list_28)
col_sum = np.sum(arr_28, axis=0)
# 若符合tar_arr条件,则为要求的排班方案
if (col_sum == tar_arr).all():
result_1.append(arr_28)
list_28.clear()
# for i, plan in enumerate(result_1):
# print(plan, "<- 方案{}".format(i + 1))
# print("-" * 50)
print("1)共有{}种设备排班方案.".format(len(result_1)))
print("*" * 50)
# 第二问结果
result_2 = list()
add = True
for plan in result_1:
for dev in plan:
# 设备出现连续启用三天的情况
if 3 in (
dev[0] + dev[1] + dev[2], dev[1] + dev[2] + dev[3],
dev[2] + dev[3] + dev[4], dev[3] + dev[4] + dev[5],
dev[4] + dev[5] + dev[6], dev[5] + dev[6] + dev[0]
):
add = False
break
if add:
result_2.append(plan)
add = True
# for i, plan in enumerate(result_2):
# print(plan, "<- 方案{}".format(i + 1))
# print("-" * 50)
print("2)共有{}种设备排班方案.".format(len(result_2)))
运行结果:
1)共有150种设备排班方案.
**************************************************
2)共有4种设备排班方案.