先看看单机上跑法。精确解是不可能了,近似解法有很多,说说最简单的:
和MST的Prim算法差不多,每次选最小权的边,直到选中所有的点。
- Choose the edge with the smallest weight (the "cheapest" edge), randomly breaking ties
- Keep choosing the "cheapest" edge unless it (a) closes a smaller circuit OR (b) results in 3 selected edges coming out of a single vertex
- Continue until the Hamilton Circuit is complete
Repetitive Nearest Neighbor Algorithm
Greedy的方法
- Start at a vertex
- Travel to the vertex that you haven’t been to yet whose path has the smallest weight (If there is a tie, pick randomly.)
- Continue until you travel to all vertices
- DO NNA for each vertex
- Choose the best solution
这里是一个RNNA的程序:
/* 500 cities Hamilton Path */
/* Repetitive Nearest Neighbour Algorithm (RNNA) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define CITYSIZE 500
/* 15000 > distance(0,0,10000,10000) */
#define MAXDIST 15000
/* 7500000 > 15000 * (500 - 1) */
#define MAXTOTAL 7500000
/* cities informatin */
typedef struct S_c {
int id;
int x;
int y;
int visited;
} CITY;
void showcity(CITY*,int); // show city coordinate, for test
void showdist(int[][CITYSIZE], int); // show distances, for test
void showpath(int*, int, int);
double distance(int, int, int, int); // distance formula
int compare(const void *, const void *); // functor for qsort()
int find(int*,int); // look for an integer in array
int main(){
time_t start, done;
time(&start);
FILE *fin;
int i, j;
CITY city[CITYSIZE];
int tour[CITYSIZE], tmptour[CITYSIZE];
int weight[CITYSIZE][CITYSIZE]={0};
fin = fopen("cities.dat", "r");
// read cities locations
char dump; // useless information
for(i = 0; i < CITYSIZE; ++i){
fscanf(fin, "%d %c %d", &city[i].id, &dump, &city[i].x);
fscanf(fin, "%c %d", &dump, &city[i].y);
}
// calculate cities distance
for(i = 0; i < CITYSIZE; ++i){
for(j = 0; j < CITYSIZE; ++j){
if(i < j){
weight[i][j] = (int)distance(city[i].x,
city[i].y,
city[j].x,
city[j].y);
weight[j][i] = weight[i][j];
}//if end
}//for end
}// for end
int total = MAXTOTAL, tmptotal = MAXTOTAL, startCty = 0;
for(; startCty < CITYSIZE; ++startCty){
// if found better path
if(tmptotal < total){
total = tmptotal;
memcpy(tour, tmptour, sizeof(tour));
showpath(tour, CITYSIZE, total);
}
// cleanup, prepare for new search
tmptotal = 0;
for(i = 0; i < CITYSIZE; ++i) city[i].visited = 0;
int nextCty, currCty = startCty;
tmptour[0] = startCty;
city[startCty].visited = 1;
for(i = 1; i < CITYSIZE;){
int cost = MAXDIST;
for(j = 0; j < CITYSIZE; ++j){
if((cost > weight[currCty][j]) &&
(!city[j].visited) &&
(j != currCty)){
cost = weight[currCty][j];
nextCty = j;
}// if end
}// for end
// step to next city
currCty = nextCty;
// add this city into path
tmptour[i++] = currCty;
city[currCty].visited = 1;
// accumulate path length
tmptotal += cost;
}// for end
}// for end
time(&done);
printf("execution time = %d seconds/n",done - start);
}
void showdist(int array[][CITYSIZE], int size){
int i, j;
for(i = 0; i < size; ++i){
for(j = 0; j < size; ++j){
printf("%4d,", array[i][j]);
}
printf("/n");
}
}
void showcity(CITY* array, int size){
int i;
for(i = 0; i < size; ++i){
printf("%d:%d:%d:%d/n", array[i].id,
array[i].x,
array[i].y,
array[i].visited);
}// for end
}
void showpath(int* array, int size, int total){
int i;
printf("%d:", total);
for(i = 0; i < size - 1; ++i) printf("%d,", array[i]);
printf("%d/n", array[i]);
}
double distance(int x1, int y1, int x2, int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
这段程序一般用不了一秒钟,结果191133,我不知道最优解是什么,不过这500个城市的MST是14w多,哈密尔顿path一定比这个数值大,估计在15~16w上下,RNNA结果只能说马马虎虎。
加一句,数据结构很重要。。。以前都没有切身体会,这次算是学了一课。上面的RNNA是以查找点为基础实现的。以查找边为基础实现也是可以的,但是在我的机器上耗时差不多150秒!!!究其原因是因为,点只有500个,而全连通的边达到500×500,查找效率及其低下。所以,千万要想好了才动手啊~~