ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] 求助:怎么利用VBA实现排列组合,进行分组排序?谢谢!

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-7-23 12:30 | 显示全部楼层
我也写了一个,思路和上面各位有所不同。
运行结果遵循:占用宿舍最少;同舍中无校友这两条原则。
分配成功的条件是:同校生数量不大于最小宿舍数。
我测试过,即使在较为极端的情况下,也能获得满意的分配方案。【极端情况:几所学校的生源数量都接近或等于最小宿舍数】
有兴趣的朋友,不妨设计一些极端数据,检验一下。
  1. Option Explicit

  2. Public Type StudentInfo
  3.     No As Long
  4.     Name As String
  5.     School As String
  6. End Type

  7. Public Const RANDOM_COUNT As Long = 100     '随机化次数
  8. Public Const DORM_COUNT As Long = 6       '核定宿舍人数

  9. Sub 宿舍分配2()

  10.     Dim i&, j&, k&, iRow&, t#
  11.     Dim BoyCount&, GirlCount&       '男、女生人数
  12.     Dim arrData                     '源数据
  13.     Dim arrBoy() As StudentInfo     '男生信息
  14.     Dim arrGirl() As StudentInfo    '女生信息
  15.     Dim uInfo As StudentInfo
  16.    
  17.     t = Timer
  18.     iRow = Range("A" & Rows.Count).End(xlUp).Row
  19.    
  20.     arrData = Range("A2:E" & iRow)
  21.    
  22.     '统计男、女生人数
  23.     For i = 1 To UBound(arrData)
  24.         If arrData(i, 4) = "男" Then BoyCount = BoyCount + 1 Else GirlCount = GirlCount + 1
  25.     Next i
  26.       
  27.     '创建男、女生信息数组
  28.     ReDim arrBoy(1 To BoyCount)
  29.     ReDim arrGirl(1 To GirlCount)
  30.    
  31.     For i = 1 To UBound(arrData)
  32.         uInfo.No = i:  uInfo.School = arrData(i, 3)
  33.         If arrData(i, 4) = "男" Then
  34.             j = j + 1: arrBoy(j) = uInfo
  35.         Else
  36.             k = k + 1: arrGirl(k) = uInfo
  37.         End If
  38.     Next i
  39.    
  40.     '分配宿舍
  41.     If Not AllotDorm(arrData, arrBoy, "男舍-") Then MsgBox "男舍分配失败!": Exit Sub
  42.     If Not AllotDorm(arrData, arrGirl, "女舍-") Then MsgBox "女舍分配失败!": Exit Sub
  43.    
  44.     Range("A2:E" & iRow) = arrData

  45.     刷新数据透视表

  46.     MsgBox "分配成功!耗时:" & Format(Timer - t, "0.0000s ")

  47. End Sub

  48. '---------------------------------------------------------------------------------------
  49. '
  50. '分配:按序提取一个学生,挨个宿舍查看,如果该宿舍人数小于DORM_COUNT人并无该生的校友,则
  51. '分入该舍,接着提取下一名学生。否则查看下一个宿舍。如果所有宿舍都不满足分入该生的条件,
  52. '则重新随机化学生的分配顺序,并重新分配。当随机化次数超过RANDOM_COUNT次时,宣布分配失败,
  53. '并退出。
  54. '---------------------------------------------------------------------------------------
  55. Function AllotDorm(arrData, arrStudent() As StudentInfo, ByVal Sex As String) As Boolean
  56.     Dim i&, j&, k&, iCount&, Number&
  57.     Dim uInfo As StudentInfo
  58.     Dim arrDorm()                   '男舍,二维数组,第一维有两个单元,第一个单元用于统计宿舍人数,
  59.                                     '第二个单元用于存放分入该舍学生的母校信息;第二维代表宿舍号。
  60.    
  61.     Number = UBound(arrStudent)     '学生人数
  62.    
  63. Start:
  64.     ReDim arrDorm(1 To 2, 1 To Application.RoundUp(Number / DORM_COUNT, 0)) '创建宿舍
  65.    
  66.     '随机化分配顺序
  67.     For i = 1 To Number
  68.         k = Int((Number - i + 1) * Rnd()) + i
  69.         uInfo = arrStudent(k): arrStudent(k) = arrStudent(i): arrStudent(i) = uInfo
  70.     Next i
  71.    
  72.     '分配
  73.     For i = 1 To Number
  74.         For j = 1 To UBound(arrDorm, 2)
  75.             If arrDorm(1, j) < DORM_COUNT And InStr(1, arrDorm(2, j), arrStudent(i).School) = 0 Then
  76.                 arrDorm(1, j) = arrDorm(1, j) + 1
  77.                 arrDorm(2, j) = arrDorm(2, j) & arrStudent(i).School & ","
  78.                 arrData(arrStudent(i).No, 5) = Sex & Format(j, "00")
  79.                 Exit For
  80.             End If
  81.         Next j
  82.                
  83.         If j > UBound(arrDorm, 2) Then
  84.             iCount = iCount + 1
  85.             If iCount < RANDOM_COUNT Then GoTo Start Else Exit Function
  86.         End If
  87.     Next i
  88.    
  89.     AllotDorm = True
  90.    
  91. End Function

  92. Sub 刷新数据透视表()
  93.     ActiveSheet.PivotTables("数据透视表2").PivotCache.Refresh
  94.     [I:aa].ColumnWidth = 3
  95. End Sub
复制代码
宿舍分配.rar (29.06 KB, 下载次数: 32)

TA的精华主题

TA的得分主题

发表于 2012-7-23 13:01 | 显示全部楼层
三坛老窖 发表于 2012-7-23 12:30
我也写了一个,思路和上面各位有所不同。
运行结果遵循:占用宿舍最少;同舍中无校友这两条原则。
分配成 ...

看不懂,能不能详细解释一下?

TA的精华主题

TA的得分主题

发表于 2012-7-23 13:08 | 显示全部楼层
小花鹿 发表于 2012-7-23 13:01
看不懂,能不能详细解释一下?

是总体思路看不懂,还是某条语句或语句块看不懂?

TA的精华主题

TA的得分主题

发表于 2012-7-23 13:27 | 显示全部楼层
我的思路是这样的:

1、编麻花,就是每个学校抽一个人,组成6个排序
2、排到后面会出现重复,将重复的人随机往前挪几个人的位置,直至检查没有重复学校的编在一起为止。

这个算法一般不会发生死机,但可能会慢一点。

TA的精华主题

TA的得分主题

发表于 2012-7-23 13:33 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
liucqa 发表于 2012-7-23 13:27
我的思路是这样的:

1、编麻花,就是每个学校抽一个人,组成6个排序

给个图看看呗。

点评

俺只有思路,没写代码。以前用这个思路写过一个考号前后左右不同班的排序  发表于 2012-7-23 14:24

TA的精华主题

TA的得分主题

发表于 2012-7-23 13:38 | 显示全部楼层
三坛老窖 发表于 2012-7-23 13:08
是总体思路看不懂,还是某条语句或语句块看不懂?

每条语句没逐个看,暂时是总体思路不懂,另外我没用过自定义函数。

TA的精华主题

TA的得分主题

发表于 2012-7-23 14:06 | 显示全部楼层
liucqa 发表于 2012-7-23 13:27
我的思路是这样的:

1、编麻花,就是每个学校抽一个人,组成6个排序

就这么个思路,到现实的代码之间,还有很多路要走……

并且,也许有很多问题、bug需要解决。


呵呵。


随机性如何保证,或如何体现,也是个疑问。

TA的精华主题

TA的得分主题

发表于 2012-7-23 14:14 | 显示全部楼层
三坛老窖 发表于 2012-7-23 12:30
我也写了一个,思路和上面各位有所不同。
运行结果遵循:占用宿舍最少;同舍中无校友这两条原则。
分配成 ...

我认为不应该偏题,
不能按照【小花鹿】自作主张增加的条件: 【部分学校人数超多!】去考虑问题。

因为这样一来,同一宿舍中没有同校学生的条件就是发傻的行为。
(按实际情形也应该不会这样子的。)


因此,希望你回到主题,就用楼主的数据,
看如何编写代码,一次性随机抽取分配学生,保证除了零头都是6个学生一个宿舍,且没有同校学生。




TA的精华主题

TA的得分主题

发表于 2012-7-23 14:16 | 显示全部楼层
目前,只有我写的代码,能够保证代码反复运行,

都能一次性得到具有充分随机性的分配方案,而不会死循环。




TA的精华主题

TA的得分主题

发表于 2012-7-23 15:30 | 显示全部楼层
zhaogang1960 发表于 2012-7-19 13:17
短信收到,请测试:

赵老师,你好!
请问,我想一次性把多列数据装进字典做关键词,并求和,不知道怎么用法,请赐教!如附件,我想一次性把多列数据装进字典做关键词,并求和,不知道怎么用法,请赐教!http://club.excelhome.net/thread-896860-1-1.html
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-18 21:53 , Processed in 0.043001 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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