ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 1424|回复: 37

[求助] 求助排(均衡)值班表

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-3-30 07:09 | 显示全部楼层 |阅读模式
本帖最后由 wlianke 于 2024-4-8 17:27 编辑


结合各位大师的算法,自己胡乱编了一个代码,21个人以内随便排,间隔合理,值勤均匀。在此非常感谢所有提供帮助的大师!代码非常乱,算法也不科学,但已经够用了!有心的大师能否帮助修整代码,成分感激!!!
求助老师们,能否实现以下功能:
一、共14个人参与值班,每天1个人值班。
二、每个周mod周日都进行人员调整,目的是不能让某人老是周六或周日值班,所以,需要每个人都能轮到周六或周日值班
三、每个人的值班的频次要均等,不能有的人值的多,有的人值的少。例如,王聪聪两个月值了四天班,而邢金两个月只值了两三或者三天班。
四、排班周期可以一个月,也可以两个月,也可以三个月,只要大家都能轮一遍。
五、排好班后值完这一轮,最好下一轮可以继续用这个,或者可以重排,但原则还是每个人的值班频次均等。
image.png

  1. 模块1:
  2. Sub test() '统计排班情况
  3. Dim arr, brr(1 To 10000, 1 To 8)
  4. Dim dic
  5. Set dic = CreateObject("scripting.dictionary")
  6. arr = Sheets("排班表").Range("B2:D" & Sheets("排班表").Cells(Rows.Count, "B").End(xlUp).Row)
  7. For x = 1 To UBound(arr)
  8. If Not dic.exists(arr(x, 2)) Then Set dic(arr(x, 2)) = CreateObject("scripting.dictionary")
  9. dic(arr(x, 2))(arr(x, 1)) = dic(arr(x, 2))(arr(x, 1)) + 1
  10. Next
  11. brr(1, 1) = "姓名"
  12. brr(1, 2) = "周一"
  13. brr(1, 3) = "周二"
  14. brr(1, 4) = "周三"
  15. brr(1, 5) = "周四"
  16. brr(1, 6) = "周五"
  17. brr(1, 7) = "周六"
  18. brr(1, 8) = "周日"
  19. c = 2
  20. For Each aa In dic.keys
  21.     brr(c, 1) = aa
  22.     For Each bb In dic(aa).keys
  23.         For n = 2 To 8
  24.             If brr(1, n) = bb Then
  25.             brr(c, n) = dic(aa)(bb)
  26.             End If
  27.         Next
  28.     Next
  29.     c = c + 1
  30. Next
  31. Sheets("排班情况").[A2].Resize(UBound(brr), UBound(brr, 2)) = brr
  32. With Sheets("排班情况")
  33.      With .Range("A1").CurrentRegion
  34.           .Borders.LineStyle = xlContinuous '加边框
  35.           .HorizontalAlignment = xlCenter '居中
  36.      End With
  37.           .Cells.EntireColumn.AutoFit '列自适应
  38. End With
  39. Sheets("排班情况").Activate
  40. End Sub
  41. 模块2
  42. Option Explicit
  43. Public pbname '排班人员数组
  44. Public rs As Integer  '参与排班的人数
  45. Public zqarray '排班周期数组
  46. Public ksrq As Date  '开始日期
  47. Public arr '人数大于等于21人时的数组
  48. Sub pbsub()
  49. Dim i As Integer, ts As Integer, x As Integer, y As Integer
  50. pbname = Sheets("基础数据").Range("B2:D" & Sheets("基础数据").Range("B10000").End(xlUp).Row)
  51. ReDim Preserve pbname(1 To UBound(pbname), 1 To 4)
  52.     For i = 1 To UBound(pbname)
  53.         pbname(i, 4) = i - 1
  54.     Next
  55. ksrq = Sheets("基础数据").Range("A2")
  56. rs = UBound(pbname)
  57. If rs > 21 Then MsgBox "抱歉,暂不支持21人以上的排班!": End
  58. If rs Mod 4 = 0 Then
  59.     ts = UBound(pbname) * 7
  60. Else
  61.     ts = UBound(pbname) * 2 * 7
  62. End If
  63. ReDim crr(1 To ts)
  64. ReDim zqarray(0 To ts, 1 To 5)
  65.     zqarray(0, 1) = "日期": zqarray(0, 2) = "星期": zqarray(0, 3) = "姓名": zqarray(0, 4) = "部门": zqarray(0, 5) = "电话"
  66. If rs Mod 4 = 0 Then
  67.     For i = 1 To UBound(zqarray)
  68.         zqarray(i, 1) = ksrq + (i - 1)
  69.                 zqarray(i, 2) = Format(Weekday(zqarray(i, 1), 1), "aaa")
  70.                 crr(i) = y
  71.              For x = 1 To rs
  72.                  If pbname(x, 4) = crr(i) Then zqarray(i, 3) = pbname(x, 1): zqarray(i, 4) = pbname(x, 2): zqarray(i, 5) = pbname(x, 3)
  73.              Next x
  74.         If y < rs - 1 Then y = y + 1 Else y = 0
  75.     Next
  76. ElseIf rs = 21 Then
  77.     Call shiyan
  78.     For i = 1 To UBound(zqarray)
  79.         zqarray(i, 1) = ksrq + (i - 1)
  80.         zqarray(i, 2) = Format(Weekday(zqarray(i, 1), 1), "aaa")
  81.             For y = 1 To rs
  82.                 If pbname(y, 4) = arr(i - 1) Then zqarray(i, 3) = pbname(y, 1): zqarray(i, 4) = pbname(y, 2): zqarray(i, 5) = pbname(y, 3)
  83.             Next
  84.     Next i
  85. Else
  86.     For i = 1 To UBound(zqarray)
  87.         zqarray(i, 1) = ksrq + (i - 1): crr(i) = (i - 1 + Int((WorksheetFunction.WeekNum(zqarray(i, 1), 2) + 1) / 2) * 2) Mod rs
  88.         zqarray(i, 2) = Format(Weekday(zqarray(i, 1), 1), "aaa")
  89.         For x = 1 To rs
  90.             If pbname(x, 4) = crr(i) Then zqarray(i, 3) = pbname(x, 1): zqarray(i, 4) = pbname(x, 2): zqarray(i, 5) = pbname(x, 3)
  91.         Next
  92.     Next
  93. End If
  94. Sheets("排班表").UsedRange.Clear 'Contents
  95. Sheets("排班表").Range("A1").Resize(UBound(zqarray) + 1, UBound(zqarray, 2)) = zqarray
  96. With Sheets("排班表")
  97.      With .Range("A1").CurrentRegion
  98.           .Borders.LineStyle = xlContinuous '加边框
  99.           .HorizontalAlignment = xlCenter '居中
  100.      End With
  101.           .Cells.EntireColumn.AutoFit '列自适应
  102. End With
  103. Sheets("排班表").Activate
  104. End Sub

  105. Public Sub shiyan()
  106. Dim cs As Integer, x As Integer, y As Integer, z As Integer, u As Integer, v  As Integer, w As Integer, brr
  107. ReDim brr(0 To rs - 1)
  108. For x = 0 To UBound(brr)
  109.     brr(x) = x
  110. Next x
  111. ReDim arr(0 To (UBound(brr) + 1) * 2 * 7 - 1)
  112. x = 0
  113. y = 0
  114. For z = v To (UBound(arr) + 1)
  115.     For x = w To UBound(brr)
  116.        arr(v) = brr(x)
  117.        v = v + 1
  118.     Next x
  119.     If UBound(brr) - w < UBound(brr) Then
  120.         w = (UBound(brr) + 1) - (UBound(brr) + 1 - w) - 1
  121.        For y = 0 To w
  122.            arr(v) = brr(y)
  123.            v = v + 1
  124.        Next
  125.        w = w + 1
  126.     End If
  127.     w = w + 1
  128.     If v >= (UBound(arr) + 1) Then GoTo 100
  129. Next z
  130. 100:
  131. End Sub
复制代码


均衡排班表含周六日及节假日(21人以内).rar

43.74 KB, 下载次数: 7

TA的精华主题

TA的得分主题

发表于 2024-3-30 08:35 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-3-30 08:53 | 显示全部楼层

您这公式试了一下,值周日的总是值周日,值周六的也总是值周六

TA的精华主题

TA的得分主题

发表于 2024-3-30 10:18 | 显示全部楼层
简单规则轮流:
B15=INDEX(B$1:B$14,MOD(MATCH(B14,B$1:B$14,)+IF(MOD(ROW(),14)=1,2),14)+1)

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2024-3-30 10:27 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
参与一下。我采用了一种比较偷懒的方法,把休息日按人名顺序正向排序,工作日按人名顺序倒序排序。

排班表(求助).zip

16.78 KB, 下载次数: 8

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-3-30 10:45 | 显示全部楼层
1245752336 发表于 2024-3-30 10:27
参与一下。我采用了一种比较偷懒的方法,把休息日按人名顺序正向排序,工作日按人名顺序倒序排序。

你好,感谢您的帮助,能尽量避免连续值班吗,就是每个人的值班间隔尽可能大于10天以上

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-3-30 11:24 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
山菊花 发表于 2024-3-30 10:18
简单规则轮流:
B15=INDEX(B$1:B$14,MOD(MATCH(B14,B$1:B$14,)+IF(MOD(ROW(),14)=1,2),14)+1)

感谢您的帮助

TA的精华主题

TA的得分主题

发表于 2024-3-30 12:07 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
4.1至7.7, 期间98天,其中有28个周末日,70个平时日,14人分,正好平均分配,每人5天平时日期+2天周末日期,按此98天一循环不就达到目的了?

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-3-30 12:14 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
Excel表哥在此 发表于 2024-3-30 12:07
4.1至7.7, 期间98天,其中有28个周末日,70个平时日,14人分,正好平均分配,每人5天平时日期+2天周末日期 ...

是的,但是需要避免某个人的值班日间隔太短,所以排起来还是挺麻烦的

TA的精华主题

TA的得分主题

发表于 2024-3-30 13:09 | 显示全部楼层
wlianke 发表于 2024-3-30 12:14
是的,但是需要避免某个人的值班日间隔太短,所以排起来还是挺麻烦的

这个可以不是那么麻烦的......
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-17 21:48 , Processed in 0.050159 second(s), 17 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表