'有点意思,这问题还具有一定的通用性
'同组2位选手及裁判都为不同学校,有解优先局部多次随机
Option Explicit
Sub 同组选手及裁判不同校()
Dim a(2), i, j, p, m, n, cnt, d, t
Set d = CreateObject("scripting.dictionary")
a(0) = [a3].CurrentRegion.Offset(1).Resize(, 2).Value
Call rnddata(a(0), 1, UBound(a(0)) - 1, 1, 2)
Call bsort(a(0), 1, UBound(a(0)) - 1, 1, 2, 2)
ReDim pos(1 To UBound(a(0)) - 1, 1 To 3)
For i = 1 To UBound(a(0)) - 1
If a(0)(i, 2) <> a(0)(i + 1, 2) Then
cnt = cnt + 1
pos(cnt, 1) = p + 1: pos(cnt, 2) = i: pos(cnt, 3) = i - p
p = i
End If
Next
Call bsort(pos, 1, cnt, 1, 3, 3)
p = 0
For i = 1 To cnt
If pos(i, 3) <> pos(i + 1, 3) Then
Call rnddata(pos, p + 1, i, 1, 3)
p = i
End If
Next
For i = 1 To cnt
d(a(0)(pos(i, 1), 2)) = i
Next
a(1) = [d3].CurrentRegion.Offset(1).Resize(, 2).Value
For i = 1 To UBound(a(1)) - 2
For j = i + 1 To UBound(a(1)) - 1
If d(a(1)(i, 2)) > d(a(1)(j, 2)) Then
t = a(1)(i, 1): a(1)(i, 1) = a(1)(j, 1): a(1)(j, 1) = t
t = a(1)(i, 2): a(1)(i, 2) = a(1)(j, 2): a(1)(j, 2) = t
End If
Next
Next
a(2) = a(1)
For i = 1 To pos(1, 3)
a(1)(i, 1) = a(2)(i + (UBound(a(2)) - 1) - pos(1, 3), 1)
a(1)(i, 2) = a(2)(i + (UBound(a(2)) - 1) - pos(1, 3), 2)
Next
For i = pos(1, 3) + 1 To UBound(a(1)) - 1
a(1)(i, 1) = a(2)(i - pos(1, 3), 1)
a(1)(i, 2) = a(2)(i - pos(1, 3), 2)
Next
ReDim b(1 To UBound(a(0)) - 1, 1 To 5) As String
Do
For i = 1 To cnt
If pos(i, 1) <= pos(i, 2) Then
m = m + 1
b(m, 2) = a(0)(pos(i, 1), 1): b(m, 3) = a(0)(pos(i, 1), 2)
pos(i, 1) = pos(i, 1) + 1
If m Mod 2 = 0 Then
n = n + 1
b(m - 1, 4) = a(1)(n, 1): b(m - 1, 5) = a(1)(n, 2)
Exit For
End If
End If
Next
Loop Until m = UBound(a(0)) - 1
Randomize
For i = 1 To UBound(b) Step 2
n = (Int(Rnd * (UBound(b) / 2)) + 1) * 2 - 1
For j = 2 To UBound(b, 2)
t = b(i, j): b(i, j) = b(n, j): b(n, j) = t
t = b(i + 1, j): b(i + 1, j) = b(n + 1, j): b(n + 1, j) = t
Next
If Rnd < 0.5 Then
For j = 2 To 3
t = b(i, j): b(i, j) = b(i + 1, j): b(i + 1, j) = t
Next
End If
b(i, 1) = Format(i, "0座位"): b(i + 1, 1) = Format(i + 1, "0座位")
Next
If check(b) = False Then MsgBox "!": Exit Sub
[h4].Resize(UBound(b), UBound(b, 2)) = b
End Sub
Function check(a) As Boolean
Dim i
For i = 1 To UBound(a) Step 2
If a(i, 3) = a(i, 5) Or a(i + 1, 3) = _
a(i, 5) Or a(i, 3) = a(i + 1, 3) Then Exit Function
Next
check = True
End Function
Function bsort(a, first, last, left, right, key)
Dim i, j, k, t
For i = first To last - 1
For j = first To last + first - 1 - i
If a(j, key) < a(j + 1, key) Then
For k = left To right
t = a(j, k): a(j, k) = a(j + 1, k): a(j + 1, k) = t
Next
End If
Next
Next
End Function
Function rnddata(a, first, last, left, right)
Dim i As Long, j As Long, n As Long, cnt As Long, t
cnt = last - first + 1
Randomize
For i = first To last
n = Int(Rnd * cnt)
For j = left To right
t = a(i, j): a(i, j) = a(first + n, j): a(first + n, j) = t
Next
Next
End Function