Run the final solution-reduction pass in both directions, since

Gareth managed to find an example (10x8#458168771440033 in r6289)
where running it in only one direction failed to eliminate an
obviously redundant piece of path.

[originally from svn r6290]
[r6289 == b25fcc3f2621b0b41f3ae7cdabe57ed07f62d2c2]
This commit is contained in:
Simon Tatham
2005-09-11 14:22:32 +00:00
parent b25fcc3f26
commit 3d3d00991a

View File

@ -1160,7 +1160,7 @@ static char *solve_game(game_state *state, game_state *currstate,
} }
} }
#ifdef TSP_DIAGNOSTICS #ifndef TSP_DIAGNOSTICS
printf("before reduction, moves are "); printf("before reduction, moves are ");
x = nodes[circuit[0]] / DP1 % w; x = nodes[circuit[0]] / DP1 % w;
y = nodes[circuit[0]] / DP1 / w; y = nodes[circuit[0]] / DP1 / w;
@ -1198,6 +1198,9 @@ static char *solve_game(game_state *state, game_state *currstate,
*/ */
while (1) { while (1) {
int oldlen = circuitlen; int oldlen = circuitlen;
int dir;
for (dir = +1; dir >= -1; dir -= 2) {
for (i = 0; i < wh; i++) for (i = 0; i < wh; i++)
unvisited[i] = 0; unvisited[i] = 0;
@ -1220,31 +1223,41 @@ static char *solve_game(game_state *state, game_state *currstate,
if (i < wh) if (i < wh)
break; break;
for (i = j = 0; i < circuitlen; i++) { for (i = j = (dir > 0 ? 0 : circuitlen-1);
i < circuitlen && i >= 0;
i += dir) {
int xy = nodes[circuit[i]] / DP1; int xy = nodes[circuit[i]] / DP1;
if (currstate->grid[xy] == GEM && unvisited[xy] > 1) { if (currstate->grid[xy] == GEM && unvisited[xy] > 1) {
unvisited[xy]--; unvisited[xy]--;
} else if (currstate->grid[xy] == GEM || i == circuitlen-1) { } else if (currstate->grid[xy] == GEM || i == circuitlen-1) {
/* /*
* circuit[i] collects a gem for the only time, or is * circuit[i] collects a gem for the only time,
* the last node in the circuit. Therefore it cannot be * or is the last node in the circuit.
* removed; so we now want to replace the path from * Therefore it cannot be removed; so we now
* circuit[j] to circuit[i] with a bfs-shortest path. * want to replace the path from circuit[j] to
* circuit[i] with a bfs-shortest path.
*/ */
int k, dest, ni, ti, thisdist; int p, q, k, dest, ni, ti, thisdist;
#ifdef TSP_DIAGNOSTICS /*
printf("optimising section from %d - %d\n", j, i); * Set up the upper and lower bounds of the
* reduced section.
*/
p = min(i, j);
q = max(i, j);
#ifndef TSP_DIAGNOSTICS
printf("optimising section from %d - %d\n", p, q);
#endif #endif
for (k = 0; k < n; k++) for (k = 0; k < n; k++)
dist[k] = -1; dist[k] = -1;
head = tail = 0; head = tail = 0;
dist[circuit[j]] = 0; dist[circuit[p]] = 0;
list[tail++] = circuit[j]; list[tail++] = circuit[p];
while (head < tail && dist[circuit[i]] < 0) { while (head < tail && dist[circuit[q]] < 0) {
int ni = list[head++]; int ni = list[head++];
for (k = edgei[ni]; k < edgei[ni+1]; k++) { for (k = edgei[ni]; k < edgei[ni+1]; k++) {
int ti = edges[k]; int ti = edges[k];
@ -1255,22 +1268,25 @@ static char *solve_game(game_state *state, game_state *currstate,
} }
} }
thisdist = dist[circuit[i]]; thisdist = dist[circuit[q]];
assert(thisdist >= 0 && thisdist <= i-j); assert(thisdist >= 0 && thisdist <= q-p);
memmove(circuit+j+thisdist, circuit+i, memmove(circuit+p+thisdist, circuit+q,
(circuitlen - i) * sizeof(int)); (circuitlen - q) * sizeof(int));
circuitlen -= i-j; circuitlen -= q-p;
i = j + thisdist; q = p + thisdist;
circuitlen += i-j; circuitlen += q-p;
#ifdef TSP_DIAGNOSTICS if (dir > 0)
printf("new section runs from %d - %d\n", j, i); i = q; /* resume loop from the right place */
#ifndef TSP_DIAGNOSTICS
printf("new section runs from %d - %d\n", p, q);
#endif #endif
dest = i; dest = q;
assert(dest >= 0); assert(dest >= 0);
ni = circuit[i]; ni = circuit[q];
while (1) { while (1) {
/* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */ /* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
@ -1289,16 +1305,18 @@ static char *solve_game(game_state *state, game_state *currstate,
} }
/* /*
* Now re-increment the visit counts for the new * Now re-increment the visit counts for the
* path. * new path.
*/ */
while (++j < i) { while (++p < q) {
int xy = nodes[circuit[j]] / DP1; int xy = nodes[circuit[p]] / DP1;
if (currstate->grid[xy] == GEM) if (currstate->grid[xy] == GEM)
unvisited[xy]++; unvisited[xy]++;
} }
#ifdef TSP_DIAGNOSTICS j = i;
#ifndef TSP_DIAGNOSTICS
printf("during reduction, circuit is"); printf("during reduction, circuit is");
for (k = 0; k < circuitlen; k++) { for (k = 0; k < circuitlen; k++) {
int nc = nodes[circuit[k]]; int nc = nodes[circuit[k]];
@ -1327,7 +1345,7 @@ static char *solve_game(game_state *state, game_state *currstate,
} }
} }
#ifdef TSP_DIAGNOSTICS #ifndef TSP_DIAGNOSTICS
printf("after reduction, moves are "); printf("after reduction, moves are ");
x = nodes[circuit[0]] / DP1 % w; x = nodes[circuit[0]] / DP1 % w;
y = nodes[circuit[0]] / DP1 / w; y = nodes[circuit[0]] / DP1 / w;
@ -1347,10 +1365,12 @@ static char *solve_game(game_state *state, game_state *currstate,
} }
printf("\n"); printf("\n");
#endif #endif
}
/* /*
* If we've managed an entire reduction pass and not made * If we've managed an entire reduction pass in each
* the solution any shorter, we're _really_ done. * direction and not made the solution any shorter, we're
* _really_ done.
*/ */
if (circuitlen == oldlen) if (circuitlen == oldlen)
break; break;