Add iterated local search to solver for more stable results
This commit is contained in:
98
main.go
98
main.go
@@ -1066,48 +1066,76 @@ func handleSolve(db *sql.DB) http.HandlerFunc {
|
|||||||
return currentScore
|
return currentScore
|
||||||
}
|
}
|
||||||
|
|
||||||
for restart := 0; restart < 50; restart++ {
|
randomPlacement := func() bool {
|
||||||
if restart == 0 {
|
perm := rand.Perm(len(groupList))
|
||||||
copy(assignment, initialAssignment)
|
for i := range roomCap { roomCap[i] = roomSize }
|
||||||
} else {
|
for _, pi := range perm {
|
||||||
perm := rand.Perm(len(groupList))
|
grp := groupList[pi]
|
||||||
for i := range roomCap { roomCap[i] = roomSize }
|
placed := false
|
||||||
ok := true
|
order := rand.Perm(numRooms)
|
||||||
for _, pi := range perm {
|
for _, room := range order {
|
||||||
grp := groupList[pi]
|
if roomCap[room] < len(grp) { continue }
|
||||||
placed := false
|
valid := true
|
||||||
order := rand.Perm(numRooms)
|
for _, member := range grp {
|
||||||
for _, room := range order {
|
for p := range mustApart {
|
||||||
if roomCap[room] < len(grp) { continue }
|
partner := -1
|
||||||
valid := true
|
if p[0] == member { partner = p[1] }
|
||||||
for _, member := range grp {
|
if p[1] == member { partner = p[0] }
|
||||||
for p := range mustApart {
|
if partner >= 0 && assignment[partner] == room {
|
||||||
partner := -1
|
valid = false
|
||||||
if p[0] == member { partner = p[1] }
|
break
|
||||||
if p[1] == member { partner = p[0] }
|
|
||||||
if partner >= 0 && assignment[partner] == room {
|
|
||||||
valid = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !valid { break }
|
|
||||||
}
|
}
|
||||||
if !valid { continue }
|
if !valid { break }
|
||||||
for _, member := range grp { assignment[member] = room }
|
|
||||||
roomCap[room] -= len(grp)
|
|
||||||
placed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if !placed {
|
|
||||||
ok = false
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
if !valid { continue }
|
||||||
|
for _, member := range grp { assignment[member] = room }
|
||||||
|
roomCap[room] -= len(grp)
|
||||||
|
placed = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if !ok {
|
if !placed { return false }
|
||||||
copy(assignment, initialAssignment)
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
perturb := func(src []int, count int) {
|
||||||
|
copy(assignment, src)
|
||||||
|
indices := rand.Perm(len(uniqueGroups))
|
||||||
|
if count > len(indices) { count = len(indices) }
|
||||||
|
for _, gi := range indices[:count] {
|
||||||
|
grp := groups[uniqueGroups[gi]]
|
||||||
|
oldRoom := assignment[grp[0]]
|
||||||
|
rooms := rand.Perm(numRooms)
|
||||||
|
for _, room := range rooms {
|
||||||
|
if room == oldRoom { continue }
|
||||||
|
if roomCount(assignment, room)+len(grp) > roomSize { continue }
|
||||||
|
for _, m := range grp { assignment[m] = room }
|
||||||
|
if feasible(assignment) { break }
|
||||||
|
for _, m := range grp { assignment[m] = oldRoom }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(assignment, initialAssignment)
|
||||||
|
s := hillClimb(assignment)
|
||||||
|
if s > bestScore {
|
||||||
|
bestScore = s
|
||||||
|
copy(bestAssignment, assignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
for restart := 0; restart < 30; restart++ {
|
||||||
|
if randomPlacement() {
|
||||||
|
s := hillClimb(assignment)
|
||||||
|
if s > bestScore {
|
||||||
|
bestScore = s
|
||||||
|
copy(bestAssignment, assignment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ils := 0; ils < 200; ils++ {
|
||||||
|
perturb(bestAssignment, 2+rand.Intn(3))
|
||||||
s := hillClimb(assignment)
|
s := hillClimb(assignment)
|
||||||
if s > bestScore {
|
if s > bestScore {
|
||||||
bestScore = s
|
bestScore = s
|
||||||
|
|||||||
Reference in New Issue
Block a user