TSP-simple solution

先看看单机上跑法。精确解是不可能了,近似解法有很多,说说最简单的:

Cheapest Link Algorithm

和MST的Prim算法差不多,每次选最小权的边,直到选中所有的点。

  1. Choose the edge with the smallest weight (the "cheapest" edge), randomly breaking ties
  2. 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
  3. Continue until the Hamilton Circuit is complete

Repetitive Nearest Neighbor Algorithm

Greedy的方法

  1. Start at a vertex
  2. Travel to the vertex that you haven’t been to yet whose path has the smallest weight (If there is a tie, pick randomly.)
  3. Continue until you travel to all vertices
  4. DO NNA for each vertex
  5. 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,查找效率及其低下。所以,千万要想好了才动手啊~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值