Fix SA solver: track currentScore, add move-to-room, 20 restarts
This commit is contained in:
166
main.go
166
main.go
@@ -948,62 +948,132 @@ func handleSolve(db *sql.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialAssignment := make([]int, n)
|
||||||
|
copy(initialAssignment, assignment)
|
||||||
|
|
||||||
bestAssignment := make([]int, n)
|
bestAssignment := make([]int, n)
|
||||||
copy(bestAssignment, assignment)
|
copy(bestAssignment, assignment)
|
||||||
bestScore := score(assignment)
|
bestScore := score(assignment)
|
||||||
|
|
||||||
temp := 10.0
|
roomCount := func(a []int, room int) int {
|
||||||
cooling := 0.9995
|
c := 0
|
||||||
iterations := 50000
|
for _, r := range a {
|
||||||
|
if r == room { c++ }
|
||||||
for iter := 0; iter < iterations; iter++ {
|
|
||||||
i := rand.Intn(n)
|
|
||||||
j := rand.Intn(n)
|
|
||||||
if assignment[i] == assignment[j] { continue }
|
|
||||||
|
|
||||||
iRoot := ufFind(i)
|
|
||||||
jRoot := ufFind(j)
|
|
||||||
|
|
||||||
if iRoot == jRoot { continue }
|
|
||||||
|
|
||||||
iGroup := groups[iRoot]
|
|
||||||
jGroup := groups[jRoot]
|
|
||||||
|
|
||||||
iRoom := assignment[i]
|
|
||||||
jRoom := assignment[j]
|
|
||||||
|
|
||||||
roomI := 0
|
|
||||||
roomJ := 0
|
|
||||||
for _, a := range assignment {
|
|
||||||
if a == iRoom { roomI++ }
|
|
||||||
if a == jRoom { roomJ++ }
|
|
||||||
}
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
newRoomI := roomI - len(iGroup) + len(jGroup)
|
for restart := 0; restart < 20; restart++ {
|
||||||
newRoomJ := roomJ - len(jGroup) + len(iGroup)
|
if restart == 0 {
|
||||||
if newRoomI > roomSize || newRoomJ > roomSize { continue }
|
copy(assignment, initialAssignment)
|
||||||
|
|
||||||
for _, m := range iGroup { assignment[m] = jRoom }
|
|
||||||
for _, m := range jGroup { assignment[m] = iRoom }
|
|
||||||
|
|
||||||
if !feasible(assignment) {
|
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
|
||||||
for _, m := range jGroup { assignment[m] = jRoom }
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
newScore := score(assignment)
|
|
||||||
delta := newScore - bestScore
|
|
||||||
if delta > 0 || rand.Float64() < math.Exp(float64(delta)/temp) {
|
|
||||||
if newScore > bestScore {
|
|
||||||
bestScore = newScore
|
|
||||||
copy(bestAssignment, assignment)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
perm := rand.Perm(len(groupList))
|
||||||
for _, m := range jGroup { assignment[m] = jRoom }
|
for i := range roomCap { roomCap[i] = roomSize }
|
||||||
|
ok := true
|
||||||
|
for _, pi := range perm {
|
||||||
|
grp := groupList[pi]
|
||||||
|
placed := false
|
||||||
|
order := rand.Perm(numRooms)
|
||||||
|
for _, room := range order {
|
||||||
|
if roomCap[room] < len(grp) { continue }
|
||||||
|
valid := true
|
||||||
|
for _, member := range grp {
|
||||||
|
for p := range mustApart {
|
||||||
|
partner := -1
|
||||||
|
if p[0] == member { partner = p[1] }
|
||||||
|
if p[1] == member { partner = p[0] }
|
||||||
|
if partner >= 0 && assignment[partner] == room {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid { break }
|
||||||
|
}
|
||||||
|
if !valid { continue }
|
||||||
|
for _, member := range grp { assignment[member] = room }
|
||||||
|
roomCap[room] -= len(grp)
|
||||||
|
placed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !placed {
|
||||||
|
ok = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
copy(assignment, initialAssignment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentScore := score(assignment)
|
||||||
|
if currentScore > bestScore {
|
||||||
|
bestScore = currentScore
|
||||||
|
copy(bestAssignment, assignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
temp := 10.0
|
||||||
|
cooling := 0.9995
|
||||||
|
iterations := 50000
|
||||||
|
|
||||||
|
for iter := 0; iter < iterations; iter++ {
|
||||||
|
i := rand.Intn(n)
|
||||||
|
iRoot := ufFind(i)
|
||||||
|
iGroup := groups[iRoot]
|
||||||
|
iRoom := assignment[i]
|
||||||
|
|
||||||
|
if rand.Intn(2) == 0 {
|
||||||
|
targetRoom := rand.Intn(numRooms)
|
||||||
|
if targetRoom == iRoom { continue }
|
||||||
|
newCount := roomCount(assignment, targetRoom) + len(iGroup)
|
||||||
|
if newCount > roomSize { continue }
|
||||||
|
for _, m := range iGroup { assignment[m] = targetRoom }
|
||||||
|
if !feasible(assignment) {
|
||||||
|
for _, m := range iGroup { assignment[m] = iRoom }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newScore := score(assignment)
|
||||||
|
delta := newScore - currentScore
|
||||||
|
if delta >= 0 || rand.Float64() < math.Exp(float64(delta)/temp) {
|
||||||
|
currentScore = newScore
|
||||||
|
if currentScore > bestScore {
|
||||||
|
bestScore = currentScore
|
||||||
|
copy(bestAssignment, assignment)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, m := range iGroup { assignment[m] = iRoom }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
j := rand.Intn(n)
|
||||||
|
if assignment[j] == iRoom { continue }
|
||||||
|
jRoot := ufFind(j)
|
||||||
|
if iRoot == jRoot { continue }
|
||||||
|
jGroup := groups[jRoot]
|
||||||
|
jRoom := assignment[j]
|
||||||
|
newRoomI := roomCount(assignment, iRoom) - len(iGroup) + len(jGroup)
|
||||||
|
newRoomJ := roomCount(assignment, jRoom) - len(jGroup) + len(iGroup)
|
||||||
|
if newRoomI > roomSize || newRoomJ > roomSize { continue }
|
||||||
|
for _, m := range iGroup { assignment[m] = jRoom }
|
||||||
|
for _, m := range jGroup { assignment[m] = iRoom }
|
||||||
|
if !feasible(assignment) {
|
||||||
|
for _, m := range iGroup { assignment[m] = iRoom }
|
||||||
|
for _, m := range jGroup { assignment[m] = jRoom }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newScore := score(assignment)
|
||||||
|
delta := newScore - currentScore
|
||||||
|
if delta >= 0 || rand.Float64() < math.Exp(float64(delta)/temp) {
|
||||||
|
currentScore = newScore
|
||||||
|
if currentScore > bestScore {
|
||||||
|
bestScore = currentScore
|
||||||
|
copy(bestAssignment, assignment)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, m := range iGroup { assignment[m] = iRoom }
|
||||||
|
for _, m := range jGroup { assignment[m] = jRoom }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp *= cooling
|
||||||
}
|
}
|
||||||
temp *= cooling
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type roomMember struct {
|
type roomMember struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user