2011|08|
2013|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|05|06|07|08|09|10|11|12|
2016|01|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|

2018-07-23 複数拠点を通るルート計算方法 [長年日記]

/*
  gcc -g wf5.cpp -o wf5
 
  ワーシャル-フロイド法を使った複数人数を拾う経路計画(その5)
 
  参考:ゼオスTTのブログ
  http://zeosutt.hatenablog.com/entry/2015/05/05/045943
 
*/
 
#include <stdio.h>
#include <math.h>
#include <stdlib.h> 
 
typedef struct location{
  // ちなみに X,Y 軸座標は、→に+  ↑に+
  int num;
  char name[10];
  double longitude; // 経度 東経 139.691 X軸  
  double latitude;  // 緯度 北緯 35.698  Y軸 
} LOCATION;
 
LOCATION location[] = {
  {0,"A",35.896889, 139.966776},
  {1,"B",35.911303, 139.950609},
  {2,"C",35.902413, 139.950861},
  {3,"D",35.905665, 139.945430},
  {4,"E",35.891797, 139.959714},
  {5,"F",35.888019, 139.949214},
  {6,"G",35.887682, 139.945090},
  {7,"H",35.900693, 139.938919},
  {8,"I",35.898430, 139.932503},
  {9,"J",35.899640, 139.919513},
  {10,"K",35.893257, 139.934952},
  {11,"L",35.892819, 139.943374},
  {12,"M",35.887158, 139.922399},
  {13,"N",35.893778, 139.952453}
};
 
#define rad2deg(a) ((a)/M_PI * 180.0) /* rad を deg に換算するマクロ関数 */
#define deg2rad(a) ((a)/180.0 * M_PI) /* deg を rad に換算するマクロ関数 */
 
double distance_km(LOCATION* A, LOCATION* B, double *rad_up)
{
  double earth_r = 6378.137;
  
  double loRe = deg2rad(B->longitude - A->longitude); // 東西
  double laRe = deg2rad(B->latitude - A->latitude); // 南北
  
  double EWD = cos(deg2rad(A->latitude))*earth_r*loRe; // 東西距離
  double NSD = earth_r*laRe; //南北距離
  
  double distance = sqrt(pow(NSD,2)+pow(EWD,2));  
  *rad_up = atan2(NSD, EWD);
  
  return distance;
}
 
LOCATION* new_location(LOCATION* D, double diff_p_x, double diff_p_y) 
{
  double earth_r = 6378.137;
  
  double loRe = diff_p_x / earth_r / cos(deg2rad(D->latitude)); // 東西
  double laRe = diff_p_y / earth_r;  // 南北
  
  double diff_lo = rad2deg(loRe); // 東西
  double diff_la = rad2deg(laRe); // 南北
  
  static LOCATION C;
  
  C.longitude = D->longitude + diff_lo; // 東西
  C.latitude = D->latitude + diff_la; // 南北
  
  return &C;
}
 
double diff_longitude(double diff_p_x, double latitude) 
{
  double earth_r = 6378.137;
  // ↓ これが正解だけど、
  double loRe = diff_p_x / earth_r / cos(deg2rad(latitude)); // 東西
  // 面倒なので、これで統一しよう(あまり差が出ないしね)
  //double loRe = diff_p_x / earth_r / cos(deg2rad(35.700759)); // 東西
  double diff_lo = rad2deg(loRe); // 東西
  
  return diff_lo; // 東西
}
 
double diff_latitude(double diff_p_y) 
{
  double earth_r = 6378.137;
  double laRe = diff_p_y / earth_r;  // 南北
  double diff_la = rad2deg(laRe); // 南北
  
  return diff_la; // 南北
}
 
 
 
double d[14][14];  // d[i][k]:ノードiからノードkへの距離 
int next[14][14];  // ノードi から ノードj への最短経路における i の1つ後のノード
 
int main(void)
{
  // 変数の初期化
  for(int i = 0; i < 14; i++){
	for(int j = 0; j < 14; j++){
	  d[i][j] = 99999999.9; // 距離の初期化(でっかい値を入力しておく(INT_MAXは足し算の時に桁上がりが起こるので使わない)
	  next[i][j] = j; // ノードi から ノードj への最短経路における i の1つ後のノード
	}
  }
 
 
  // 確認用の表示
  printf("\n[STEP1]\n");
 
  for(int i = 0; i < 14; i++){
	for(int k = 0; k < 14; k++){
	  printf("d[%d][%d]):%f\t",i,k,d[i][k]);
	  printf("next[%d][%d]):%d\n",i,k,next[i][k]);
	}
  }
 
  //// ここからは実際の距離を手書き
 
  for(int i = 0; i < 14; i++){
	d[i][i] = 0; //// 同じノードへの距離は0になるので、上書き
  }
 
  double rad_up;
  d[0][1]  = distance_km(&location[0], &location[1], &rad_up);
  d[0][4]  = distance_km(&location[0], &location[4], &rad_up);
 
  d[1][0]  = distance_km(&location[1], &location[0], &rad_up);
  d[1][3]  = distance_km(&location[1], &location[3], &rad_up);
 
  d[2][3]  = distance_km(&location[2], &location[3], &rad_up);
  d[2][4]  = distance_km(&location[2], &location[4], &rad_up);
  d[2][13]  = distance_km(&location[2], &location[13], &rad_up);
 
  d[3][1]  = distance_km(&location[3], &location[1], &rad_up);
  d[3][2]  = distance_km(&location[3], &location[2], &rad_up);
  d[3][7]  = distance_km(&location[3], &location[7], &rad_up);
 
  d[4][0]  = distance_km(&location[4], &location[0], &rad_up);
  d[4][2]  = distance_km(&location[4], &location[2], &rad_up);
  d[4][13]  = distance_km(&location[4], &location[13], &rad_up);
 
  d[5][4]  = distance_km(&location[5], &location[4], &rad_up);
  d[5][6]  = distance_km(&location[5], &location[6], &rad_up);
  d[5][13]  = distance_km(&location[5], &location[13], &rad_up);
 
  d[6][5]  = distance_km(&location[6], &location[5], &rad_up);
  d[6][11]  = distance_km(&location[6], &location[11], &rad_up);
  d[6][12]  = distance_km(&location[6], &location[12], &rad_up);
 
  d[7][3]  = distance_km(&location[7], &location[3], &rad_up);
  d[7][8]  = distance_km(&location[7], &location[8], &rad_up);
  d[7][11]  = distance_km(&location[7], &location[11], &rad_up);
 
  d[8][7]  = distance_km(&location[8], &location[7], &rad_up);
  d[8][9]  = distance_km(&location[8], &location[9], &rad_up);
  d[8][10]  = distance_km(&location[8], &location[10], &rad_up);
 
  d[9][8]  = distance_km(&location[9], &location[8], &rad_up);
 
  d[10][8]  = distance_km(&location[10], &location[8], &rad_up);
  d[10][11]  = distance_km(&location[10], &location[11], &rad_up);
 
  d[11][6]  = distance_km(&location[11], &location[6], &rad_up);
  d[11][7]  = distance_km(&location[11], &location[7], &rad_up);
  d[11][10]  = distance_km(&location[11], &location[10], &rad_up);
 
  d[12][6]  = distance_km(&location[12], &location[6], &rad_up);
 
  d[13][2]  = distance_km(&location[13], &location[2], &rad_up);
  d[13][4]  = distance_km(&location[13], &location[4], &rad_up);
  d[13][5]  = distance_km(&location[13], &location[5], &rad_up);
 
  
  // 確認用の表示
  printf("\n[STEP2]\n");
 
  for(int i = 0; i < 14; i++){
	for(int k = 0; k < 14; k++){
	  printf("d[%d][%d]):%f\t",i,k,d[i][k]);
	  printf("next[%d][%d]):%d\n",i,k,next[i][k]);
	}
  }
 
  // 経路長計算
  for (int k =0; k < 14; k++){
	for (int i =0; i < 14; i++){
	  for(int j = 0; j < 14; j++){
		if(d[i][j] > d[i][k] + d[k][j]){
 
		  d[i][j] = d[i][k] + d[k][j];
		  next[i][j] = next[i][k]; //更新処理
		}
	  }
	}
  }
 
  // 計算結果
  printf("\n[STEP3]\n");
 
  for(int i = 0; i < 14; i++){
	for(int k = 0; k < 14; k++){
	  printf("d[%d][%d]):%f\t",i,k,d[i][k]);
	  printf("next[%d][%d]):%d\n",i,k,next[i][k]);
	}
  }
 
  // 経路パス表示
 
  printf("\n[Path]\n");
  for(int i = 0; i < 14; i++){
	for(int k = 0; k < 14; k++){
	  
	  int cur;
	  printf("d[%d][%d]: ",i,k);
	  
	  for (cur = i; cur != k; cur = next[cur][k]){
        printf("%d -> ", cur);
	  }
	  printf("%d\n", k);
	}
  }
 
 
  // では、ここで   N(13):出発値 A(0),D(3),H(7),K(10)の最短距離を求めるアルゴリズムを考えてみる
  // 総当たり戦でいくなら、さほど難しくはない
  // バス、タクシー程度であれば、スケールはあまり考えなくても良い
 
  int p[] = {13, 12, 0, 8, 3};
  int res_p[] = {-1, -1, -1, -1, -1};
 
  double dis_old = 9999.9;
  double dis_new;
 
  int i,j,k,m;
  double dis_i, dis_k, dis_j, dis_m;
 
  for (i = 1; i < 5; i++){
	dis_i = d[p[0]][p[i]];
 
	for (k = 1; k < 5; k++){
	  if (k == i){
		continue;
	  }
	  dis_k = d[p[i]][p[k]];
	  
	  for (j = 1; j < 5; j++){
		if ((j == k) || (j == i)){
		  continue;
		}
		dis_j = d[p[k]][p[j]];
 
		for (m = 1; m < 5; m++){
		  if ((m == k) || (m == i) || (m == j)){
			continue;
		  }
 
		  dis_m = d[p[j]][p[m]];
 
		  dis_new = dis_i + dis_k + dis_j + dis_m;
 
		  if (dis_new < dis_old){
			dis_old = dis_new;
			res_p[0] = 0;
			res_p[1] = i;
			res_p[2] = k;
			res_p[3] = j;
			res_p[4] = m;
 
			printf("dis_old = %f, i:%d k:%d j:%d m:%d \n", dis_old,i,k,j,m);
			printf("dis_old = %f, %d→%d→%d→%d→%d\n", dis_old,p[res_p[0]],p[res_p[1]],p[res_p[2]],p[res_p[3]],p[res_p[4]]);
 
		  }
		}
	  }
	}
  }
 
  printf("dis_old = %f, %d→%d→%d→%d→%d\n", 
		 dis_old,p[res_p[0]],p[res_p[1]],p[res_p[2]],p[res_p[3]],p[res_p[4]]);
 
  // dis_old = 13.563715, 13→0→3→9→12
 
 
  // 経路パス表示
 
  for (int n = 0; n < 4; n++){
 
	int i = p[res_p[n]];
	int k = p[res_p[n+1]];
	
	int cur;
	printf("d[%d][%d]: ",i,k);
	
	for (cur = i; cur != k; cur = next[cur][k]){
	  printf("%d -> ", cur);
	}
	printf("%d\n", k);
  }
 
}
syntax2html