What you're describing is a form of a score trap. Although Late Acceptance is likely to produce better results than Tabu Search when the score trap is present (and it's just changes 2 lines to switch to it), it's still going to affect the results badly.
Those docs describe 2 answers to get rid of the score trap:
1) Improving the score function granularity won't work in this case.
2) Course grained moves will work in this case. For example you can add a custom move factory (but keep the original moveSelectors too - or better yet benchmark with and without the original moveSelectors). Let the custom move factory generate moves that are less likely to break those constraints. For example: if visit A and B need the same vehicle, move A inside another vehicle's chain and at the same time move B to somewhere else in the same vehicle's chain (reuse CompositeMove
).
And there's a 3th way I 'll document soon (but I don't see it applying to this case easily):
3) In some cases, its possible to bake such hard constraints into the class diagram of the model (which makes them build-in hard constraints). For example in exam scheduling, if 2 ore more exams need to be at the same timeslot, only 1 exam is "the leader" and has a timeslot variable. The other exams are "herd", which means their timeslots get adjusted by a shadow variable when the leader changes.