|
|
|
@ -10,7 +10,7 @@
|
|
|
|
|
#include "gtsp-subtour.h"
|
|
|
|
|
#include "gtsp-comb.h"
|
|
|
|
|
|
|
|
|
|
int large_neighborhood_search(int *tour, struct GTSP *data, int *tour_cost);
|
|
|
|
|
int large_neighborhood_search(struct Tour *tour, struct GTSP *data, int *tour_cost);
|
|
|
|
|
|
|
|
|
|
int build_edge_map(struct GTSP *gtsp, int *edge_map);
|
|
|
|
|
|
|
|
|
@ -497,16 +497,34 @@ int GTSP_solution_found(struct BNC *bnc, struct GTSP *data, double *x)
|
|
|
|
|
UNUSED(bnc);
|
|
|
|
|
|
|
|
|
|
int rval = 0;
|
|
|
|
|
|
|
|
|
|
int tour_cost;
|
|
|
|
|
char filename[100];
|
|
|
|
|
|
|
|
|
|
double *best_val = &bnc->best_obj_val;
|
|
|
|
|
|
|
|
|
|
struct Tour* tour;
|
|
|
|
|
tour = (struct Tour*) malloc(data->cluster_count*sizeof(struct Tour));
|
|
|
|
|
|
|
|
|
|
sprintf(filename, "tmp/gtsp-m%d-n%d-s%d.out", data->cluster_count,
|
|
|
|
|
data->graph->node_count, SEED);
|
|
|
|
|
|
|
|
|
|
log_info("Writting solution to file %s\n", filename);
|
|
|
|
|
rval = GTSP_write_solution(data, filename, x);
|
|
|
|
|
abort_if(rval, "GTSP_write_solution failed");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rval = build_tour_from_x(data,tour,x);
|
|
|
|
|
abort_if(rval, "build_tour_from_x failed");
|
|
|
|
|
|
|
|
|
|
rval = large_neighborhood_search(tour, data, &tour_cost);
|
|
|
|
|
abort_if(rval, "large_neighborhood_search failed");
|
|
|
|
|
|
|
|
|
|
if(tour_cost + LP_EPSILON < *best_val){
|
|
|
|
|
log_info("Local search improve the integral solution\n");
|
|
|
|
|
log_info(" obj val = %f\n",*best_val );
|
|
|
|
|
log_info(" after LNS = %d\n",tour_cost );
|
|
|
|
|
*best_val = tour_cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_info("Checking solution...\n");
|
|
|
|
|
rval = GTSP_check_solution(data, x);
|
|
|
|
|
abort_if(rval, "GTSP_check_solution failed");
|
|
|
|
@ -807,7 +825,7 @@ int GTSP_main(int argc, char **argv)
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int build_x_from_tour(struct GTSP *data, int *tour, double *x)
|
|
|
|
|
int build_x_from_tour(struct GTSP *data, struct Tour *tour, double *x)
|
|
|
|
|
{
|
|
|
|
|
int rval = 0;
|
|
|
|
|
int *edge_map = 0;
|
|
|
|
@ -824,10 +842,14 @@ int build_x_from_tour(struct GTSP *data, int *tour, double *x)
|
|
|
|
|
for (int i = 0; i < node_count + edge_count; i++)
|
|
|
|
|
x[i] = 0.0;
|
|
|
|
|
|
|
|
|
|
int next_vertex = tour[0].next;
|
|
|
|
|
int current_vertex = tour[0].vertex;
|
|
|
|
|
for (int i = 0; i < data->cluster_count; i++)
|
|
|
|
|
{
|
|
|
|
|
int from = tour[i];
|
|
|
|
|
int to = tour[i + 1];
|
|
|
|
|
int from = current_vertex;
|
|
|
|
|
int to = tour[next_vertex].vertex;
|
|
|
|
|
current_vertex = tour[next_vertex].vertex;
|
|
|
|
|
next_vertex = tour[next_vertex].next;
|
|
|
|
|
|
|
|
|
|
x[from] = 1.0;
|
|
|
|
|
x[to] = 1.0;
|
|
|
|
@ -842,14 +864,14 @@ int build_x_from_tour(struct GTSP *data, int *tour, double *x)
|
|
|
|
|
int inital_tour_value(struct GTSP *data, int *tour_cost, double *x)
|
|
|
|
|
{
|
|
|
|
|
int rval = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cluster_count = data->cluster_count;
|
|
|
|
|
|
|
|
|
|
int *tour = 0;
|
|
|
|
|
struct Tour *tour = 0;
|
|
|
|
|
int *uncovered_sets = 0;
|
|
|
|
|
int *cluster_in_tour = 0;
|
|
|
|
|
|
|
|
|
|
tour = (int *) malloc((cluster_count + 1) * sizeof(int));
|
|
|
|
|
tour = (struct Tour *) malloc((cluster_count + 1) * sizeof(struct Tour));
|
|
|
|
|
uncovered_sets = (int *) malloc((cluster_count - 1) * sizeof(int));
|
|
|
|
|
cluster_in_tour = (int *) malloc(cluster_count * sizeof(int));
|
|
|
|
|
abort_if(!tour, "could not allocate tour");
|
|
|
|
@ -863,49 +885,86 @@ int inital_tour_value(struct GTSP *data, int *tour_cost, double *x)
|
|
|
|
|
if (data->node_to_cluster[0] != i)
|
|
|
|
|
{
|
|
|
|
|
uncovered_sets[cluster_num] = i;
|
|
|
|
|
cluster_num += 1;
|
|
|
|
|
cluster_num ++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int new_vertex = 1;
|
|
|
|
|
tour[0] = 0;
|
|
|
|
|
int new_vertex = 1, cost;
|
|
|
|
|
|
|
|
|
|
tour[0].vertex = 0;
|
|
|
|
|
cluster_in_tour[0] = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (new_vertex < data->cluster_count)
|
|
|
|
|
{
|
|
|
|
|
int min_vertex = -1;
|
|
|
|
|
int min_dist_vertex = -1;
|
|
|
|
|
int min_cost = INT_MAX;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < data->graph->node_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!cluster_in_tour[data->node_to_cluster[i]])
|
|
|
|
|
{
|
|
|
|
|
for (int k = 0; k < new_vertex; k++)
|
|
|
|
|
{
|
|
|
|
|
int cost = data->dist_matrix[i][tour[k]];
|
|
|
|
|
if (cost < min_cost)
|
|
|
|
|
{
|
|
|
|
|
min_cost = cost;
|
|
|
|
|
min_vertex = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (cluster_in_tour[data->node_to_cluster[i]]) continue;
|
|
|
|
|
|
|
|
|
|
for (int k = 0; k < new_vertex; k++)
|
|
|
|
|
{
|
|
|
|
|
cost = data->dist_matrix[i][tour[k].vertex];
|
|
|
|
|
if (cost < min_cost)
|
|
|
|
|
{ min_cost = cost;
|
|
|
|
|
min_dist_vertex = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(min_vertex >= 0);
|
|
|
|
|
|
|
|
|
|
tour[new_vertex] = min_vertex;
|
|
|
|
|
cluster_in_tour[data->node_to_cluster[min_vertex]] = 1;
|
|
|
|
|
|
|
|
|
|
assert(min_dist_vertex >= 0);
|
|
|
|
|
int cluster_to_insert = data->node_to_cluster[min_dist_vertex];
|
|
|
|
|
cluster_in_tour[cluster_to_insert] = 1;
|
|
|
|
|
|
|
|
|
|
min_cost = INT_MAX;
|
|
|
|
|
|
|
|
|
|
int insertion_cost = -1, best_pose = -1, best_vertex = -1;
|
|
|
|
|
|
|
|
|
|
for (int k=0 ; k < data->clusters[cluster_to_insert].size; k++){
|
|
|
|
|
for(int j = 0; j < new_vertex; j++){
|
|
|
|
|
int vertex_to_insert = data->clusters[cluster_to_insert].nodes[k];
|
|
|
|
|
if (new_vertex ==1){
|
|
|
|
|
int vertex1 = tour[0].vertex;
|
|
|
|
|
insertion_cost = data->dist_matrix[vertex_to_insert][vertex1]
|
|
|
|
|
+ data->dist_matrix[vertex1][vertex_to_insert];
|
|
|
|
|
}else{
|
|
|
|
|
int vertex1 = tour[j].vertex;
|
|
|
|
|
int vertex2 = tour[tour[j].next].vertex;
|
|
|
|
|
insertion_cost = data->dist_matrix[vertex1][vertex_to_insert]
|
|
|
|
|
+ data->dist_matrix[vertex_to_insert][vertex2] -
|
|
|
|
|
data->dist_matrix[vertex1][vertex2];
|
|
|
|
|
}
|
|
|
|
|
if(insertion_cost < min_cost){
|
|
|
|
|
min_cost = insertion_cost;
|
|
|
|
|
best_pose = j;
|
|
|
|
|
best_vertex = vertex_to_insert;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tour[new_vertex].vertex = best_vertex;
|
|
|
|
|
tour[new_vertex].prev = best_pose;
|
|
|
|
|
|
|
|
|
|
if (new_vertex ==1){
|
|
|
|
|
tour[new_vertex].next = best_pose;
|
|
|
|
|
tour[best_pose].prev = new_vertex;
|
|
|
|
|
}else{
|
|
|
|
|
int temp_vertex = tour[best_pose].next;
|
|
|
|
|
tour[new_vertex].next = temp_vertex;
|
|
|
|
|
tour[temp_vertex].prev = new_vertex;
|
|
|
|
|
}
|
|
|
|
|
tour[best_pose].next = new_vertex;
|
|
|
|
|
|
|
|
|
|
new_vertex += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tour[data->cluster_count] = 0;
|
|
|
|
|
tour[data->cluster_count].vertex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rval = large_neighborhood_search(tour, data, tour_cost);
|
|
|
|
|
abort_if(rval, "large_neighborhood_search failed");
|
|
|
|
|
|
|
|
|
|
//tour_cost = optimize_vertex_in_cluster(tour, data);
|
|
|
|
|
|
|
|
|
|
log_info("Initial upper-bound: %d \n", *tour_cost);
|
|
|
|
|
|
|
|
|
|
rval = build_x_from_tour(data, tour, x);
|
|
|
|
@ -989,47 +1048,30 @@ int two_opt(struct Tour *tour, struct GTSP *data)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int large_neighborhood_search(int *tour, struct GTSP *data, int *tour_cost)
|
|
|
|
|
int large_neighborhood_search(struct Tour *tour, struct GTSP *data, int *tour_cost)
|
|
|
|
|
{
|
|
|
|
|
int rval = 0;
|
|
|
|
|
struct Tour *vertex_seq = 0;
|
|
|
|
|
|
|
|
|
|
int cluster_count = data->cluster_count;
|
|
|
|
|
int *clusters = data->node_to_cluster;
|
|
|
|
|
int **dist_matrix = data->dist_matrix;
|
|
|
|
|
struct Cluster *vertex_set = data->clusters;
|
|
|
|
|
|
|
|
|
|
vertex_seq = (struct Tour *) malloc(cluster_count * sizeof(struct Tour));
|
|
|
|
|
abort_if(!vertex_seq, "could not allocate vertex_seq");
|
|
|
|
|
|
|
|
|
|
//Construct the list
|
|
|
|
|
for (int i = 0; i < cluster_count; i++)
|
|
|
|
|
{
|
|
|
|
|
vertex_seq[i].vertex = tour[i];
|
|
|
|
|
if (i == 0)
|
|
|
|
|
vertex_seq[i].prev = cluster_count - 1;
|
|
|
|
|
else
|
|
|
|
|
vertex_seq[i].prev = i - 1;
|
|
|
|
|
|
|
|
|
|
if (i == cluster_count - 1)
|
|
|
|
|
vertex_seq[i].next = 0;
|
|
|
|
|
else
|
|
|
|
|
vertex_seq[i].next = i + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//LNS starts
|
|
|
|
|
for (int iter = 0; iter < 1000; iter++)
|
|
|
|
|
for (int iter = 0; iter < 2000; iter++)
|
|
|
|
|
{
|
|
|
|
|
//Delete a vertex
|
|
|
|
|
//Delete a random vertex
|
|
|
|
|
|
|
|
|
|
int delete_vertex = rand() % (cluster_count - 1) + 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int prev_vertex = tour[delete_vertex].prev;
|
|
|
|
|
int next_vertex = tour[delete_vertex].next;
|
|
|
|
|
|
|
|
|
|
int prev_vertex = vertex_seq[delete_vertex].prev;
|
|
|
|
|
int next_vertex = vertex_seq[delete_vertex].next;
|
|
|
|
|
|
|
|
|
|
vertex_seq[prev_vertex].next = next_vertex;
|
|
|
|
|
vertex_seq[next_vertex].prev = prev_vertex;
|
|
|
|
|
tour[prev_vertex].next = next_vertex;
|
|
|
|
|
tour[next_vertex].prev = prev_vertex;
|
|
|
|
|
|
|
|
|
|
int cluster_to_insert = clusters[vertex_seq[delete_vertex].vertex];
|
|
|
|
|
int cluster_to_insert = clusters[tour[delete_vertex].vertex];
|
|
|
|
|
|
|
|
|
|
int best_pose = -1;
|
|
|
|
|
int best_vertex = -1;
|
|
|
|
@ -1039,11 +1081,11 @@ int large_neighborhood_search(int *tour, struct GTSP *data, int *tour_cost)
|
|
|
|
|
{
|
|
|
|
|
int vertex_to_insert = vertex_set[cluster_to_insert].nodes[i];
|
|
|
|
|
|
|
|
|
|
int next_edge = vertex_seq[0].next;
|
|
|
|
|
int next_edge = tour[0].next;
|
|
|
|
|
for (int j = 1; j < cluster_count; j++)
|
|
|
|
|
{
|
|
|
|
|
int vertex1 = vertex_seq[next_edge].vertex;
|
|
|
|
|
int vertex2 = vertex_seq[vertex_seq[next_edge].next].vertex;
|
|
|
|
|
int vertex1 = tour[next_edge].vertex;
|
|
|
|
|
int vertex2 = tour[tour[next_edge].next].vertex;
|
|
|
|
|
|
|
|
|
|
int insert_cost = dist_matrix[vertex1][vertex_to_insert] +
|
|
|
|
|
dist_matrix[vertex_to_insert][vertex2] -
|
|
|
|
@ -1056,31 +1098,34 @@ int large_neighborhood_search(int *tour, struct GTSP *data, int *tour_cost)
|
|
|
|
|
best_vertex = vertex_to_insert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_edge = vertex_seq[next_edge].next;
|
|
|
|
|
next_edge = tour[next_edge].next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(best_pose >= 0);
|
|
|
|
|
assert(best_vertex >= 0);
|
|
|
|
|
|
|
|
|
|
next_vertex = vertex_seq[best_pose].next;
|
|
|
|
|
vertex_seq[delete_vertex].prev = best_pose;
|
|
|
|
|
vertex_seq[delete_vertex].vertex = best_vertex;
|
|
|
|
|
vertex_seq[delete_vertex].next = next_vertex;
|
|
|
|
|
vertex_seq[best_pose].next = delete_vertex;
|
|
|
|
|
vertex_seq[next_vertex].prev = delete_vertex;
|
|
|
|
|
|
|
|
|
|
rval = optimize_vertex_in_cluster(vertex_seq, data);
|
|
|
|
|
next_vertex = tour[best_pose].next;
|
|
|
|
|
tour[delete_vertex].prev = best_pose;
|
|
|
|
|
tour[delete_vertex].vertex = best_vertex;
|
|
|
|
|
tour[delete_vertex].next = next_vertex;
|
|
|
|
|
tour[best_pose].next = delete_vertex;
|
|
|
|
|
tour[next_vertex].prev = delete_vertex;
|
|
|
|
|
|
|
|
|
|
rval = optimize_vertex_in_cluster(tour, data);
|
|
|
|
|
abort_if(rval, "optimize_vertex_in_cluster failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rval = two_opt(vertex_seq, data);
|
|
|
|
|
|
|
|
|
|
rval = K_opt(tour, data);
|
|
|
|
|
abort_if(rval, "two_opt failed");
|
|
|
|
|
|
|
|
|
|
*tour_cost = list_length(vertex_seq, data);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rval = two_opt(tour, data);
|
|
|
|
|
abort_if(rval, "two_opt failed");
|
|
|
|
|
|
|
|
|
|
*tour_cost = list_length(tour, data);
|
|
|
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
|
if (vertex_seq) free(vertex_seq);
|
|
|
|
|
//if (vertex_seq) free(vertex_seq);
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1134,4 +1179,138 @@ void print_list(struct Tour *tour, struct GTSP *data)
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int K_opt(struct Tour* tour, struct GTSP *data)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int cluster_count = data->cluster_count;
|
|
|
|
|
int l;
|
|
|
|
|
|
|
|
|
|
for(int i = 0 ; i < cluster_count - 3; i++){
|
|
|
|
|
int location_in_path = 0;
|
|
|
|
|
|
|
|
|
|
for(int k = 0; k < i; k++)
|
|
|
|
|
location_in_path = tour[location_in_path].next;
|
|
|
|
|
|
|
|
|
|
int current_vertex = tour[location_in_path].vertex;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int k = 3; k < cluster_count - i - 2; k++){
|
|
|
|
|
int first_next_location = tour[location_in_path].next;
|
|
|
|
|
int first_next_vertex = tour[tour[location_in_path].next].vertex;
|
|
|
|
|
int next_location = tour[location_in_path].next;
|
|
|
|
|
for(l = 0; l < k; l++){
|
|
|
|
|
next_location = tour[next_location].next;
|
|
|
|
|
}
|
|
|
|
|
int next_vertex = tour[next_location].vertex;
|
|
|
|
|
int next_next_location = tour[next_location].next;
|
|
|
|
|
|
|
|
|
|
int next_next_vertex = tour[next_next_location].vertex;
|
|
|
|
|
|
|
|
|
|
if(next_next_vertex == current_vertex) break;
|
|
|
|
|
|
|
|
|
|
int cost1 = data->dist_matrix[current_vertex][first_next_vertex] +
|
|
|
|
|
data->dist_matrix[next_vertex][next_next_vertex];
|
|
|
|
|
int cost2 = data->dist_matrix[current_vertex][next_vertex] +
|
|
|
|
|
data->dist_matrix[first_next_vertex][next_next_vertex];
|
|
|
|
|
|
|
|
|
|
if(cost2 < cost1)
|
|
|
|
|
{
|
|
|
|
|
int tmp_location = next_location;
|
|
|
|
|
for(int m =0 ; m < l + 1; m++)
|
|
|
|
|
{
|
|
|
|
|
int tmp_vertex = tour[tmp_location].next;
|
|
|
|
|
tour[tmp_location].next = tour[tmp_location].prev;
|
|
|
|
|
tour[tmp_location].prev = tmp_vertex;
|
|
|
|
|
tmp_location = tour[tmp_location].next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tour[location_in_path].next = next_location;
|
|
|
|
|
tour[next_location].prev = location_in_path;
|
|
|
|
|
|
|
|
|
|
tour[first_next_location].next = next_next_location;
|
|
|
|
|
|
|
|
|
|
tour[next_next_location].prev = first_next_location;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int build_tour_from_x(struct GTSP *data, struct Tour *tour, double *x)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int rval = 0;
|
|
|
|
|
int *cluster_mark = 0;
|
|
|
|
|
|
|
|
|
|
struct Node **stack = 0;
|
|
|
|
|
int stack_top = 0;
|
|
|
|
|
|
|
|
|
|
struct Graph *graph = data->graph;
|
|
|
|
|
const int node_count = graph->node_count;
|
|
|
|
|
|
|
|
|
|
cluster_mark = (int *) malloc(data->cluster_count * sizeof(int));
|
|
|
|
|
abort_if(!cluster_mark, "could not allocate cluster_mark");
|
|
|
|
|
|
|
|
|
|
stack = (struct Node **) malloc(graph->node_count * sizeof(struct Node *));
|
|
|
|
|
abort_if(!stack, "could not allocate stack");
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < node_count; i++)
|
|
|
|
|
graph->nodes[i].mark = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < data->cluster_count; i++)
|
|
|
|
|
cluster_mark[i] = 0;
|
|
|
|
|
|
|
|
|
|
int initial;
|
|
|
|
|
for (initial = 0; initial < node_count; initial++)
|
|
|
|
|
if (x[initial] > 1.0 - LP_EPSILON) break;
|
|
|
|
|
|
|
|
|
|
abort_if(initial == node_count, "no initial node");
|
|
|
|
|
|
|
|
|
|
stack[stack_top++] = &graph->nodes[initial];
|
|
|
|
|
graph->nodes[initial].mark = 1;
|
|
|
|
|
|
|
|
|
|
tour[0].vertex = graph->nodes[initial].index;
|
|
|
|
|
int next_vertex = 1;
|
|
|
|
|
|
|
|
|
|
while (stack_top > 0)
|
|
|
|
|
{
|
|
|
|
|
struct Node *n = stack[--stack_top];
|
|
|
|
|
cluster_mark[data->node_to_cluster[n->index]]++;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < n->degree; i++)
|
|
|
|
|
{
|
|
|
|
|
struct Adjacency *adj = &n->adj[i];
|
|
|
|
|
struct Node *neighbor = adj->neighbor;
|
|
|
|
|
|
|
|
|
|
if (neighbor->mark) continue;
|
|
|
|
|
if (x[node_count + adj->edge->index] < LP_EPSILON) continue;
|
|
|
|
|
|
|
|
|
|
stack[stack_top++] = neighbor;
|
|
|
|
|
tour[next_vertex].vertex = neighbor->index;
|
|
|
|
|
next_vertex++;
|
|
|
|
|
neighbor->mark = 1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i =0; i < data->cluster_count; i++){
|
|
|
|
|
if(i == 0){
|
|
|
|
|
tour[i].prev = data->cluster_count - 1;
|
|
|
|
|
}else{
|
|
|
|
|
tour[i].prev = i-1;
|
|
|
|
|
}
|
|
|
|
|
if(i == data->cluster_count - 1){
|
|
|
|
|
tour[i].next = 0;
|
|
|
|
|
}else{
|
|
|
|
|
tour[i].next = i+1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
|
if (stack) free(stack);
|
|
|
|
|
if (cluster_mark) free(cluster_mark);
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|