|
我也写了一个,思路和上面各位有所不同。
运行结果遵循:占用宿舍最少;同舍中无校友这两条原则。
分配成功的条件是:同校生数量不大于最小宿舍数。
我测试过,即使在较为极端的情况下,也能获得满意的分配方案。【极端情况:几所学校的生源数量都接近或等于最小宿舍数】
有兴趣的朋友,不妨设计一些极端数据,检验一下。- Option Explicit
- Public Type StudentInfo
- No As Long
- Name As String
- School As String
- End Type
- Public Const RANDOM_COUNT As Long = 100 '随机化次数
- Public Const DORM_COUNT As Long = 6 '核定宿舍人数
- Sub 宿舍分配2()
- Dim i&, j&, k&, iRow&, t#
- Dim BoyCount&, GirlCount& '男、女生人数
- Dim arrData '源数据
- Dim arrBoy() As StudentInfo '男生信息
- Dim arrGirl() As StudentInfo '女生信息
- Dim uInfo As StudentInfo
-
- t = Timer
- iRow = Range("A" & Rows.Count).End(xlUp).Row
-
- arrData = Range("A2:E" & iRow)
-
- '统计男、女生人数
- For i = 1 To UBound(arrData)
- If arrData(i, 4) = "男" Then BoyCount = BoyCount + 1 Else GirlCount = GirlCount + 1
- Next i
-
- '创建男、女生信息数组
- ReDim arrBoy(1 To BoyCount)
- ReDim arrGirl(1 To GirlCount)
-
- For i = 1 To UBound(arrData)
- uInfo.No = i: uInfo.School = arrData(i, 3)
- If arrData(i, 4) = "男" Then
- j = j + 1: arrBoy(j) = uInfo
- Else
- k = k + 1: arrGirl(k) = uInfo
- End If
- Next i
-
- '分配宿舍
- If Not AllotDorm(arrData, arrBoy, "男舍-") Then MsgBox "男舍分配失败!": Exit Sub
- If Not AllotDorm(arrData, arrGirl, "女舍-") Then MsgBox "女舍分配失败!": Exit Sub
-
- Range("A2:E" & iRow) = arrData
- 刷新数据透视表
- MsgBox "分配成功!耗时:" & Format(Timer - t, "0.0000s ")
- End Sub
- '---------------------------------------------------------------------------------------
- '
- '分配:按序提取一个学生,挨个宿舍查看,如果该宿舍人数小于DORM_COUNT人并无该生的校友,则
- '分入该舍,接着提取下一名学生。否则查看下一个宿舍。如果所有宿舍都不满足分入该生的条件,
- '则重新随机化学生的分配顺序,并重新分配。当随机化次数超过RANDOM_COUNT次时,宣布分配失败,
- '并退出。
- '---------------------------------------------------------------------------------------
- Function AllotDorm(arrData, arrStudent() As StudentInfo, ByVal Sex As String) As Boolean
- Dim i&, j&, k&, iCount&, Number&
- Dim uInfo As StudentInfo
- Dim arrDorm() '男舍,二维数组,第一维有两个单元,第一个单元用于统计宿舍人数,
- '第二个单元用于存放分入该舍学生的母校信息;第二维代表宿舍号。
-
- Number = UBound(arrStudent) '学生人数
-
- Start:
- ReDim arrDorm(1 To 2, 1 To Application.RoundUp(Number / DORM_COUNT, 0)) '创建宿舍
-
- '随机化分配顺序
- For i = 1 To Number
- k = Int((Number - i + 1) * Rnd()) + i
- uInfo = arrStudent(k): arrStudent(k) = arrStudent(i): arrStudent(i) = uInfo
- Next i
-
- '分配
- For i = 1 To Number
- For j = 1 To UBound(arrDorm, 2)
- If arrDorm(1, j) < DORM_COUNT And InStr(1, arrDorm(2, j), arrStudent(i).School) = 0 Then
- arrDorm(1, j) = arrDorm(1, j) + 1
- arrDorm(2, j) = arrDorm(2, j) & arrStudent(i).School & ","
- arrData(arrStudent(i).No, 5) = Sex & Format(j, "00")
- Exit For
- End If
- Next j
-
- If j > UBound(arrDorm, 2) Then
- iCount = iCount + 1
- If iCount < RANDOM_COUNT Then GoTo Start Else Exit Function
- End If
- Next i
-
- AllotDorm = True
-
- End Function
- Sub 刷新数据透视表()
- ActiveSheet.PivotTables("数据透视表2").PivotCache.Refresh
- [I:aa].ColumnWidth = 3
- End Sub
复制代码
宿舍分配.rar
(29.06 KB, 下载次数: 32)
|
|