情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/ /* 巡回セールスマン問題 */ /* 反復改善法 */ /* coded by Y.Suganuma */ /****************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <time.h> #include "MT.h" int kyori(int, int *, int **); /*************************/ /* クラスIterationの定義 */ /*************************/ class Iteration { int **city; //都市の位置データ int max_try; // 最大試行回数 int n_city; // 都市の数 int out_d; // 表示間隔 int **rg; // 都市間の距離 int *seq_w1; // 都市を訪れる順序(ワーク) int *seq_w2; // 都市を訪れる順序(ワーク) int neib; // 近傍(2 or 3) int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n回毎に出力(負の時はファイル) int out_m; // 出力方法 // =-1 : 出力しない // =0 : すべてを出力 // =1 : 評価値だけを出力(最終結果だけはすべてを出力) int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 char o_file[100]; // 出力ファイル名 public: int *seq; // 都市を訪れる順序 Iteration(long, char *); // コンストラクタ Iteration (int, int, int, int, int, int, int, char *, int **); // コンストラクタ Iteration(); // コンストラクタ ~Iteration(); // デストラクタ int Optimize(); // 最適化の実行 int Change(int *); // 改善 void Output(int, int, int); // 出力 }; /****************************/ /* コンストラクタ */ /* seed : 乱数の初期値 */ /* name : ファイル名 */ /****************************/ Iteration::Iteration (long seed, char *name) { double x, y; int ct, i1, i2, sw; FILE *in; // 乱数の初期設定 init_genrand(seed); // ファイルのオープン in = fopen(name, "r"); if (in == NULL) { printf("***error データファイル名が不適当\n"); exit(1); } // 基本データ fscanf(in, "%*s %d %*s %d %*s %d %*s %d", &n_city, &max_try, &sel, &neib); fscanf(in, "%*s %d %*s %d", &out_lvl, &out_m); fscanf(in, "%*s %s %*s %d", o_file, &out_d); // 都市の位置データ city = new int * [n_city]; for (i1 = 0; i1 < n_city; i1++) { city[i1] = new int [2]; fscanf(in, "%d %d", &city[i1][0], &city[i1][1]); } // ファイルのクローズ fclose(in); // 距離テーブルの作成 rg = new int * [n_city]; for (i1 = 0; i1 < n_city; i1++) { rg[i1] = new int [n_city]; for (i2 = i1+1; i2 < n_city; i2++) { x = city[i2][0] - city[i1][0]; y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(sqrt(x * x + y * y) + 0.5); } } for (i1 = 1; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } // 都市を訪れる順序(初期設定) seq = new int [n_city]; seq_w1 = new int [n_city]; seq_w2 = new int [n_city]; for (i1 = 0; i1 < n_city; i1++) { sw = 0; while (sw == 0) { ct = (int)(genrand_real3() * n_city); if (ct >= n_city) ct = n_city - 1; seq[i1] = ct; sw = 1; for (i2 = 0; i2 < i1 && sw > 0; i2++) { if (ct == seq[i2]) sw = 0; } } } } /******************/ /* コンストラクタ */ /******************/ Iteration::Iteration () { n_city = 0; } /****************/ /* デストラクタ */ /****************/ Iteration::~Iteration () { int i1; if (n_city > 0) { for (i1 = 0; i1 < n_city; i1++) { delete [] city[i1]; delete [] rg[i1]; } delete [] city; delete [] rg; delete[] seq; delete [] seq_w1; delete [] seq_w2; } } /****************/ /* 最適化の実行 */ /****************/ int Iteration::Optimize () { int k1, max, n_tri, sw; // 初期設定 n_tri = 0; max = kyori(n_city, seq, rg); if (out_m >= 0 && abs(out_lvl) > 0) { printf("***試行回数 %d 距離 %d\n", n_tri, -max); Output(out_lvl, n_tri, max); } // 実行 sw = 1; for (n_tri = 1; n_tri <= max_try && sw > 0; n_tri++) { // 改善 sw = Change(&max); // 出力 if (out_d > 0 && n_tri%out_d == 0) printf("***試行回数 %d 距離 %d\n", n_tri, -max); if (out_m >= 0 && abs(out_lvl) > 0) { if (n_tri%abs(out_lvl) == 0) Output(out_lvl, n_tri, max); } } // 最終出力 if (out_m >= 0) { n_tri--; k1 = out_m; out_m = 0; printf("***試行回数 %d 距離 %d\n", n_tri, -max); Output(out_lvl, n_tri, max); out_m = k1; } return n_tri; } /*******************************/ /* 出力 */ /* sw : >=0 : 出力先未定 */ /* < 0 : ファイル */ /* n_tri : 現在の試行回数 */ /* r : 距離の負値 */ /*******************************/ void Iteration::Output(int sw, int n_tri, int r) { int i1, k = 0, n, pr; char *now; time_t aclock; FILE *out; if (sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); scanf("%d", &pr); } else pr = -1; if (pr != 0) { if (pr > 0) { out = stdout; getchar(); } else { time(&aclock); now = ctime(&aclock); out = fopen(o_file, "a"); fprintf(out, "***試行回数 %d 距離 %d 時間 %s\n", n_tri, -r, now); } if (out_m == 0) { for (i1 = 0; i1 < n_city; i1++) { n = seq[i1]; fprintf(out, " %d %d %d\n", n, city[n][0], city[n][1]); if (pr > 0) { k++; if (k == pr) { getchar(); k = 0; } } } } if (pr <= 0) fclose(out); } } /**************************************/ /* エッジの入れ替え */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int Iteration::Change(int *r_m) { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = *r_m; n3 = (int)(genrand_real3() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え seq_w1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { seq_w1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その2) seq_w1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その3) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その4) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { *r_m = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = seq_w2[i1]; } return sw; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* rg : 都市間の距離 */ /* return : 距離(負) */ /*********************************/ int kyori(int n_c, int *p, int **rg) { int i1, n1, n2, range = 0; n1 = p[0]; for (i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } /****************/ /* main program */ /****************/ int main(int argc, char *argv[]) { long *seed; int i1, n; char **i_file; FILE *in; Iteration *it; // 入力ミス if (argc <= 1) { printf("***error ファイル名を入力して下さい\n"); exit(1); } // 入力OK else { // ファイルのオープン in = fopen(argv[1], "r"); if (in == NULL) { printf("***error ファイル名が不適当です\n"); exit(1); } // 入力データファイル名の入力 fscanf(in, "%d", &n); seed = new long [n]; i_file = new char * [n]; for (i1 = 0; i1 < n; i1++) { i_file[i1] = new char [100]; fscanf(in, "%s", i_file[i1]); seed[i1] = 1000 * i1 + 1234567; } fclose(in); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { printf("\n+++++ケース %d+++++\n", i1+1); // 入力と初期設定 it = new Iteration (seed[i1], i_file[i1]); // 最適化 it->Optimize(); } } return 0; } //------------------------ケーススタディデータ(data.txt)------ /* 3 data1.txt data1.txt data2.txt */ //---------------------データファイル(data1.txt)------------ /* 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------データファイル(data2.txt)------------ /* 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 */ //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include<stdio.h>" // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" /* // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti<MT_N; mti++) { mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk<MT_N-MT_M;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk<MT_N-1;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */
/****************************/ /* 巡回セールスマン問題 */ /* 反復改善法 */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.Random; import java.util.Date; import java.util.StringTokenizer; import java.awt.*; import java.awt.event.*; /*************************/ /* クラスIterationの定義 */ /*************************/ class Iteration { private int max_try; // 最大試行回数 private int neib; // 近傍(2 or 3) private int out_d; // 表示間隔 private int [][] rg; // 都市間の距離 private int [] seq_w1; // 都市を訪れる順序(ワーク) private int [] seq_w2; // 都市を訪れる順序(ワーク) private int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n回毎に出力(負の時はファイル) private int out_m; // 出力方法 // =-1 : 出力しない // =0 : すべてを出力 // =1 : 評価値だけを出力(最終結果だけはすべてを出力) private int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 private String o_file; // 出力ファイル名 private Win_it wn; // Win_itオブジェクト private Random rn; // 乱数 int [][] city; //都市の位置データ int n_city; // 都市の数 int n_tri; // 試行回数 int [] seq; // 都市を訪れる順序 int n_eg; // 交換した枝の数 int [] eg; // 交換した枝 int range; // 現在の評価値 int display; // 画面表示 // =0 : 画面表示を行わない // =1 : 結果だけを表示 // =2 : 初期状態と結果を表示 // =3 : ワンステップ毎表示 /****************************/ /* コンストラクタ */ /* seed : 乱数の初期値 */ /* name : ファイル名 */ /****************************/ Iteration (int seed, String name) throws IOException, FileNotFoundException { double x, y; int ct, i1, i2, sw; String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name)); n_tri = 0; n_eg = 0; eg = new int [6]; // 乱数の初期設定 rn = new Random(seed); // 基本データ line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); n_city = Integer.parseInt(dt.nextToken()); dt.nextToken(); max_try = Integer.parseInt(dt.nextToken()); dt.nextToken(); sel = Integer.parseInt(dt.nextToken()); dt.nextToken(); neib = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); out_lvl = Integer.parseInt(dt.nextToken()); dt.nextToken(); out_m = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); o_file = dt.nextToken(); dt.nextToken(); out_d = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); display = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); int font = Integer.parseInt(dt.nextToken()); dt.nextToken(); int width = Integer.parseInt(dt.nextToken()); int height = Integer.parseInt(dt.nextToken()); // 都市の位置データ city = new int [n_city][2]; for (i1 = 0; i1 < n_city; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); city[i1][0] = Integer.parseInt(dt.nextToken()); city[i1][1] = Integer.parseInt(dt.nextToken()); } // ファイルのクローズ in.close(); // 距離テーブルの作成 rg = new int [n_city][n_city]; for (i1 = 0; i1 < n_city; i1++) { for (i2 = i1+1; i2 < n_city; i2++) { x = city[i2][0] - city[i1][0]; y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(Math.sqrt(x * x + y * y) + 0.5); } } for (i1 = 1; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } // 都市を訪れる順序(初期設定) seq = new int [n_city]; seq_w1 = new int [n_city]; seq_w2 = new int [n_city]; for (i1 = 0; i1 < n_city; i1++) { sw = 0; while (sw == 0) { ct = (int)(rn.nextDouble() * n_city); if (ct >= n_city) ct = n_city - 1; seq[i1] = ct; sw = 1; for (i2 = 0; i2 < i1 && sw > 0; i2++) { if (ct == seq[i2]) sw = 0; } } } // Windowの生成 if (display > 0) wn = new Win_it (this, font, width, height); } /****************/ /* 最適化の実行 */ /****************/ int Optimize () throws IOException, FileNotFoundException { int k1, sw; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // ワンステップづつ実行しない場合 if (display < 3) { // 初期設定 range = kyori(n_city, seq, rg); // 初期状態の出力(図) if (display == 2) { wn.Draw(); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } // 初期状態の出力(文字) if (out_m >= 0 && Math.abs(out_lvl) > 0) { System.out.println("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); } // 実行 sw = 1; for (n_tri = 1; n_tri <= max_try && sw > 0; n_tri++) { // 改善 sw = Change(); // 出力(文字) if (out_d > 0 && n_tri%out_d == 0) System.out.println("***試行回数 " + n_tri + " 距離 " + (-range)); if (out_m >= 0 && Math.abs(out_lvl) > 0) { if (n_tri%Math.abs(out_lvl) == 0) Output(out_lvl); } } // 最終出力(図) if (display == 1 || display == 2) { wn.Draw(); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } // 最終出力(文字) if (out_m >= 0) { n_tri--; k1 = out_m; out_m = 0; System.out.println("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); out_m = k1; } } // ワンステップづつ実行する場合 else { // 初期設定 range = kyori(n_city, seq, rg); // 初期状態の出力(図) wn.Draw(); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); // 初期状態の出力(文字) if (out_m >= 0 && Math.abs(out_lvl) > 0) { System.out.println("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); } // マウスによる実行 System.out.print("\n終了したらreturnキーを押してください\n"); in.readLine(); // 最終出力(文字) if (out_m >= 0) { k1 = out_m; out_m = 0; System.out.println("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); out_m = k1; } } return n_tri; } /*******************************/ /* 出力 */ /* sw : >= 0 : 出力先未定 */ /* < 0 : ファイル */ /*******************************/ void Output(int sw) throws IOException, FileNotFoundException { int i1, k = 0, n, pr; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (sw >= 0) { System.out.print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = Integer.parseInt(in.readLine()); } else pr = -1; if (pr != 0) { if (pr > 0) out = System.out; else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(o_file, true)); out.println("***試行回数 " + n_tri + " 距離 " + (-range) + " 時間 " + now); } if (out_m == 0) { for (i1 = 0; i1 < n_city; i1++) { n = seq[i1]; out.println(" " + n + " " + city[n][0] + " " + city[n][1]); if (pr > 0) { k++; if (k == pr) { in.readLine(); k = 0; } } } } if (pr <= 0) out.close(); } } /**************************************/ /* エッジの入れ替え */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int Change() { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = range; n3 = (int)(rn.nextDouble() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え seq_w1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { seq_w1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; n_eg = 2; eg[0] = seq[n3]; eg[1] = seq[n3+1]; eg[2] = seq[k1]; eg[3] = seq[k2]; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; n_eg = 3; eg[0] = seq[n3]; eg[1] = seq[n3+1]; eg[2] = seq[i2]; eg[3] = seq[i2+1]; eg[4] = seq[k1]; eg[5] = seq[k2]; } // 入れ替え(その2) seq_w1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; n_eg = 3; eg[0] = seq[n3]; eg[1] = seq[n3+1]; eg[2] = seq[i2]; eg[3] = seq[i2+1]; eg[4] = seq[k1]; eg[5] = seq[k2]; } // 入れ替え(その3) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; n_eg = 3; eg[0] = seq[n3]; eg[1] = seq[n3+1]; eg[2] = seq[i2]; eg[3] = seq[i2+1]; eg[4] = seq[k1]; eg[5] = seq[k2]; } // 入れ替え(その4) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; n_eg = 3; eg[0] = seq[n3]; eg[1] = seq[n3+1]; eg[2] = seq[i2]; eg[3] = seq[i2+1]; eg[4] = seq[k1]; eg[5] = seq[k2]; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { range = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = seq_w2[i1]; } return sw; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* rg : 都市間の距離 */ /* return : 距離(負) */ /*********************************/ static int kyori(int n_c, int [] p, int [][] rg) { int i1, n1, n2, range = 0; n1 = p[0]; for (i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } } /**********************/ /* クラスWin_itの定義 */ /**********************/ class Win_it extends Frame { double ritu; // 表示倍率 private int font; // フォントサイズ private int min_x, max_x, min_y, max_y; // 都市の存在範囲 private int next, yoyu_x, yoyu_y; // 表示位置 private Iteration it; /***************************************/ /* コンストラクタ */ /* it_i : Iterationのオブジェクト */ /* font_i : フォントサイズ */ /* width,height : 表示範囲 */ /***************************************/ Win_it (Iteration it_i, int font_i, int width, int height) { // Frameクラスのコンストラクタの呼び出し super("巡回セールスマン問題"); // 値の設定と領域の確保 double k1, k2; int i1; it = it_i; font = font_i; next = 70; yoyu_x = 30; yoyu_y = 80; // 描画領域の計算 min_x = it.city[0][0]; max_x = it.city[0][0]; min_y = it.city[0][1]; max_y = it.city[0][1]; for (i1 = 1; i1 < it.n_city; i1++) { if (it.city[i1][0] < min_x) min_x = it.city[i1][0]; else { if (it.city[i1][0] > max_x) max_x = it.city[i1][0]; } if (it.city[i1][1] < min_y) min_y = it.city[i1][1]; else { if (it.city[i1][1] > max_y) max_y = it.city[i1][1]; } } k1 = (double)(width - 2 * yoyu_x) / (max_x - min_x); if (it.display == 3) k2 = (double)(height - yoyu_y - next) / (max_y - min_y); else k2 = (double)(height - yoyu_y - yoyu_x) / (max_y - min_y); ritu = (k1 < k2) ? k1 : k2; // ボタンの設定とWindowサイズ if (it.display == 3) { // パネルクラスの定義 Panel pnl = new Panel(); // Next ボタンの設定 Button bt = new Button("Next"); bt.addMouseListener(new ClickMouse()); pnl.add(bt); add("South", pnl); // ウィンドウの構成要素をパック pack(); // 指定された大きさにWindowサイズを変更 width = 2 * yoyu_x + (int)(ritu * (max_x - min_x)); height = yoyu_y + next + (int)(ritu * (max_y - min_y)); } else { // 指定された大きさにWindowサイズを変更 width = 2 * yoyu_x + (int)(ritu * (max_x - min_x)); height = yoyu_y + yoyu_x + (int)(ritu * (max_y - min_y)); } setSize(width, height); // ウィンドウを表示 setVisible(true); // イベントアダプタ addWindowListener(new WinEnd()); } /************/ /* 描画指示 */ /************/ void Draw() { repaint(); } /********/ /* 描画 */ /********/ public void paint (Graphics g) { int i1, k, n1, n2, size = 6, x1, x2, y1, y2; Font f; // 距離の表示 f = new Font("TimesRoman", Font.BOLD, 25); g.setFont(f); g.drawString("Length : "+Integer.toString(-it.range), yoyu_x, yoyu_y-30); // 都市番号のフォントサイズ if (font > 0) { f = new Font("TimesRoman", Font.PLAIN, font); g.setFont(f); } // 点と直線のプロット k = size / 2; for (i1 = 0; i1 < it.n_city; i1++) { n2 = it.seq[i1]; x2 = yoyu_x + (int)(ritu * (it.city[n2][0] - min_x)); y2 = yoyu_y + (int)(ritu * (max_y - it.city[n2][1])); g.fillOval(x2, y2, size, size); if (font > 0) g.drawString(Integer.toString(n2), x2+k, y2-k); if (i1 > 0) { n1 = it.seq[i1-1]; x1 = yoyu_x + (int)(ritu * (it.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - it.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); if (i1 == it.n_city-1) { n1 = it.seq[0]; x1 = yoyu_x + (int)(ritu * (it.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - it.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); } } } // 交換した元の枝を赤く描く if (it.display == 3 && it.n_eg > 0) { g.setColor(Color.red); for (i1 = 0; i1 < it.n_eg; i1++ ) { n1 = it.eg[2*i1]; x1 = yoyu_x + (int)(ritu * (it.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - it.city[n1][1])); n2 = it.eg[2*i1+1]; x2 = yoyu_x + (int)(ritu * (it.city[n2][0] - min_x)); y2 = yoyu_y + (int)(ritu * (max_y - it.city[n2][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); } } } /**********************************/ /* nextボタンが押されたときの処理 */ /**********************************/ class ClickMouse extends MouseAdapter { /************************************/ /* マウスがクリックされたときの処理 */ /************************************/ public void mouseClicked(MouseEvent e) { int sw = it.Change(); if (sw > 0) it.n_tri++; else it.n_eg = 0; repaint(); } } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } } /****************/ /* main program */ /****************/ public class Test { public static void main(String args[]) throws IOException, FileNotFoundException { int i1, n; String i_file[]; Iteration it; BufferedReader in = new BufferedReader(new FileReader(args[0])); // 入力ミス if (args.length == 0) { System.out.print("***error ファイル名を入力して下さい\n"); System.exit(1); } // 入力OK else { // 入力データファイル名の入力 n = Integer.parseInt(in.readLine()); i_file = new String [n]; for (i1 = 0; i1 < n; i1++) i_file[i1] = in.readLine(); in.close(); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { System.out.print("\n+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 it = new Iteration (1000 * i1 + 1234567, i_file[i1]); // 最適化 it.Optimize(); } } } } //------------------------ケーススタディデータ(data_j.txt)------ /* 2 data1_j.txt data2_j.txt */ //---------------------データファイル(data1_j.txt)------------ /* 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 3 都市番号 20 図の大きさ(幅,高さ) 1000 750 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------データファイル(data2_j.txt)------------ /* 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 1 都市番号 20 図の大きさ(幅,高さ) 1000 750 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 */
<?php /****************************/ /* 巡回セールスマン問題 */ /* 反復改善法 */ /* coded by Y.Suganuma */ /****************************/ /*************************/ /* クラスIterationの定義 */ /*************************/ class Iteration { private $city; //都市の位置データ private $max_try; // 最大試行回数 private $n_city; // 都市の数 private $out_d; // 表示間隔 private $rg; // 都市間の距離 private $seq_w1; // 都市を訪れる順序(ワーク) private $seq_w2; // 都市を訪れる順序(ワーク) private $neib; // 近傍(2 or 3) private $out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n回毎に出力(負の時はファイル) private $out_m; // 出力方法 // =-1 : 出力しない // =0 : すべてを出力 // =1 : 評価値だけを出力(最終結果だけはすべてを出力) private $sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 private $o_file; // 出力ファイル名 public $seq; // 都市を訪れる順序 /****************************/ /* コンストラクタ */ /* seed : 乱数の初期値 */ /* name : ファイル名 */ /****************************/ function Iteration ($seed, $name) { // 乱数の初期設定 mt_srand($seed); // ファイルのオープン $in = fopen($name, "rb"); if ($in == NULL) exit("***error データファイル名が不適当\n"); // 基本データ fscanf($in, "%*s %d %*s %d %*s %d %*s %d", $this->n_city, $this->max_try, $this->sel, $this->neib); fscanf($in, "%*s %d %*s %d", $this->out_lvl, $this->out_m); fscanf($in, "%*s %s %*s %d", $this->o_file, $this->out_d); // 都市の位置データ $this->city = array($this->n_city); for ($i1 = 0; $i1 < $this->n_city; $i1++) { $this->city[$i1] = array(2); fscanf($in, "%d %d", $this->city[$i1][0], $this->city[$i1][1]); } // ファイルのクローズ fclose($in); // 距離テーブルの作成 $this->rg = array($this->n_city); for ($i1 = 0; $i1 < $this->n_city; $i1++) { $this->rg[$i1] = array($this->n_city); for ($i2 = $i1+1; $i2 < $this->n_city; $i2++) { $x = $this->city[$i2][0] - $this->city[$i1][0]; $y = $this->city[$i2][1] - $this->city[$i1][1]; $this->rg[$i1][$i2] = round(sqrt($x * $x + $y * $y)); } } for ($i1 = 1; $i1 < $this->n_city; $i1++) { for ($i2 = 0; $i2 < $i1; $i2++) $this->rg[$i1][$i2] = $this->rg[$i2][$i1]; } // 都市を訪れる順序(初期設定) $this->seq = array($this->n_city); $this->seq_w1 = array($this->n_city); $this->seq_w2 = array($this->n_city); for ($i1 = 0; $i1 < $this->n_city; $i1++) { $sw = 0; while ($sw == 0) { $ct = intval((mt_rand() / mt_getrandmax()) * $this->n_city); if ($ct >= $this->n_city) $ct = $this->n_city - 1; $this->seq[$i1] = $ct; $sw = 1; for ($i2 = 0; $i2 < $i1 && $sw > 0; $i2++) { if ($ct == $this->seq[$i2]) $sw = 0; } } } } /****************/ /* 最適化の実行 */ /****************/ function Optimize () { // 初期設定 $n_tri = 0; $max = kyori($this->n_city, $this->seq, $this->rg); if ($this->out_m >= 0 && abs($this->out_lvl) > 0) { printf("***試行回数 %d 距離 %d\n", $n_tri, -$max); $this->Output($this->out_lvl, $n_tri, $max); } // 実行 $sw = 1; for ($n_tri = 1; $n_tri <= $this->max_try && $sw > 0; $n_tri++) { // 改善 $sw = $this->Change($max); // 出力 if ($this->out_d > 0 && $n_tri%$this->out_d == 0) printf("***試行回数 %d 距離 %d\n", $n_tri, -$max); if ($this->out_m >= 0 && abs($this->out_lvl) > 0) { if ($n_tri%abs($this->out_lvl) == 0) $this->Output($this->out_lvl, $n_tri, $max); } } // 最終出力 if ($this->out_m >= 0) { $n_tri--; $k1 = $this->out_m; $this->out_m = 0; printf("***試行回数 %d 距離 %d\n", $n_tri, -$max); $this->Output($this->out_lvl, $n_tri, $max); $this->out_m = $k1; } return $n_tri; } /*******************************/ /* 出力 */ /* sw : >=0 : 出力先未定 */ /* < 0 : ファイル */ /* n_tri : 現在の試行回数 */ /* r : 距離の負値 */ /*******************************/ function Output($sw, $n_tri, $r) { $k = 0; if ($sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); fscanf(STDIN, "%d", $pr); } else $pr = -1; if ($pr != 0) { if ($pr > 0) { $out = STDOUT; fgets(STDIN); } else { $x = getdate(); $now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒"; $out = fopen($this->o_file, "ab"); fwrite($out, "***試行回数 ".$n_tri." 距離 ".(-$r)." 時間 ".$now."%s\n"); } if ($this->out_m == 0) { for ($i1 = 0; $i1 < $this->n_city; $i1++) { $n = $this->seq[$i1]; fwrite($out, " ".$n." ".$this->city[$n][0]." ".$this->city[$n][1]."\n"); if ($pr > 0) { $k++; if ($k == $pr) { fgets(STDIN); $k = 0; } } } } if ($pr <= 0) fclose($out); } } /**************************************/ /* エッジの入れ替え */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ function Change(int &$r_m) { $ch = 0; $sw = 0; $max = $r_m; $n3 = intval((mt_rand() / mt_getrandmax()) * ($this->n_city - 2)); if ($n3 > $this->n_city-3) $n3 = $this->n_city - 3; // 2近傍 for ($i1 = 0; $i1 <= $this->n_city-3 && $ch == 0; $i1++) { if ($n3 == 0) $n1 = $this->n_city - 2; else $n1 = $this->n_city - 1; for ($i2 = $n3+2; $i2 <= $n1 && $ch == 0; $i2++) { // 枝の場所((n3,n3+1), (k1,k2)) $k1 = $i2; if ($i2 == $this->n_city-1) $k2 = 0; else $k2 = $i2 + 1; // 枝の入れ替え $this->seq_w1[0] = $this->seq[$n3]; $k = 1; for ($i3 = $k1; $i3 >= $n3+1; $i3--) { $this->seq_w1[$k] = $this->seq[$i3]; $k++; } $nn = $k2; while ($nn != $n3) { $this->seq_w1[$k] = $this->seq[$nn]; $k++; $nn++; if ($nn > $this->n_city-1) $nn = 0; } // 評価 $r = kyori($this->n_city, $this->seq_w1, $this->rg); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $this->n_city; $i3++) $this->seq_w2[$i3] = $this->seq_w1[$i3]; if ($this->sel > 0) $ch = 1; } } $n3++; if ($n3 > $this->n_city-3) $n3 = 0; } // 3近傍 if ($this->neib == 3 && $ch == 0) { for ($i1 = 0; $i1 <= $this->n_city-3 && $ch == 0; $i1++) { $n1 = $this->n_city - 2; $n2 = $this->n_city - 1; for ($i2 = $n3+1; $i2 <= $n1 && $ch == 0; $i2++) { for ($i3 = $i2+1; $i3 <= $n2 && $ch == 0; $i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) $k1 = $i3; if ($i3 == $this->n_city-1) $k2 = 0; else $k2 = $i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) $this->seq_w1[0] = $this->seq[$n3]; $k = 1; for ($i4 = $i2; $i4 >= $n3+1; $i4--) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } for ($i4 = $k1; $i4 >= $i2+1; $i4--) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->seq_w1[$k] = $this->seq[$nn]; $k++; $nn++; if ($nn > $this->n_city-1) $nn = 0; } // 評価(その1) $r = kyori($this->n_city, $this->seq_w1, $this->rg); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $this->n_city; $i3++) $this->seq_w2[$i3] = $this->seq_w1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その2) $this->seq_w1[0] = $this->seq[$n3]; $k = 1; for ($i4 = $k1; $i4 >= $i2+1; $i4--) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } for ($i4 = $n3+1; $i4 <= $i2; $i4++) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->seq_w1[$k] = $this->seq[$nn]; $k++; $nn++; if ($nn > $this->n_city-1) $nn = 0; } // 評価(その2) $r = kyori($this->n_city, $this->seq_w1, $this->rg); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $this->n_city; $i3++) $this->seq_w2[$i3] = $this->seq_w1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その3) $this->seq_w1[0] = $this->seq[$n3]; $k = 1; for ($i4 = $i2+1; $i4 <= $k1; $i4++) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } for ($i4 = $i2; $i4 >= $n3+1; $i4--) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->seq_w1[$k] = $this->seq[$nn]; $k++; $nn++; if ($nn > $this->n_city-1) $nn = 0; } // 評価(その3) $r = kyori($this->n_city, $this->seq_w1, $this->rg); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $this->n_city; $i3++) $this->seq_w2[$i3] = $this->seq_w1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その4) $this->seq_w1[0] = $this->seq[$n3]; $k = 1; for ($i4 = $i2+1; $i4 <= $k1; $i4++) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } for ($i4 = $n3+1; $i4 <= $i2; $i4++) { $this->seq_w1[$k] = $this->seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->seq_w1[$k] = $this->seq[$nn]; $k++; $nn++; if ($nn > $this->n_city-1) $nn = 0; } // 評価(その4) $r = kyori($this->n_city, $this->seq_w1, $this->rg); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $this->n_city; $i3++) $this->seq_w2[$i3] = $this->seq_w1[$i3]; if ($this->sel > 0) $ch = 1; } } } $n3++; if ($n3 > $this->n_city-3) $n3 = 0; } } // 設定 if ($sw > 0) { $r_m = $max; for ($i1 = 0; $i1 < $this->n_city; $i1++) $this->seq[$i1] = $this->seq_w2[$i1]; } return $sw; } } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* rg : 都市間の距離 */ /* return : 距離(負) */ /*********************************/ function kyori($n_c, $p, $rg) { $range = 0; $n1 = $p[0]; for ($i1 = 1; $i1 < $n_c; $i1++) { $n2 = $p[$i1]; $range -= $rg[$n1][$n2]; $n1 = $n2; } $n2 = $p[0]; $range -= $rg[$n1][$n2]; return $range; } /****************/ /* main program */ /****************/ // 入力ミス if (count($argv) <= 1) exit("***error ファイル名を入力して下さい\n"); // 入力OK else { // ファイルのオープン $in = fopen($argv[1], "rb"); if ($in == NULL) exit("***error ファイル名が不適当です\n"); // 入力データファイル名の入力 fscanf($in, "%d", $n); $seed = array($n); $i_file = array($n); for ($i1 = 0; $i1 < $n; $i1++) { fscanf($in, "%s", $i_file[$i1]); $seed[$i1] = 1000 * $i1 + 1234567; } fclose($in); // 実行(乱数の初期値を変える) for ($i1 = 0; $i1 < $n; $i1++) { printf("\n+++++ケース %d+++++\n", $i1+1); // 入力と初期設定 $it = new Iteration($seed[$i1], $i_file[$i1]); // 最適化 $it->Optimize(); } } //------------------------ケーススタディデータ(data.txt)------ /* 3 data1.txt data1.txt data2.txt */ //---------------------データファイル(data1.txt)------------ /* 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------データファイル(data2.txt)------------ /* 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 */ ?>
#################################### # 巡回セールスマン問題(反復改善法) # coded by Y.Suganuma #################################### ################################# # 距離の計算 # n_c : 都市の数 # p : 都市番号 # rg : 都市間の距離 # return : 距離 ################################# def kyori(n_c, p, rg) r = 0.0 n1 = p[0] for i1 in 1 ... n_c n2 = p[i1] r -= rg[n1][n2] n1 = n2 end n2 = p[0] r -= rg[n1][n2] return r end ######################### # クラスIterationの定義 ######################### class Iteration ############################ # コンストラクタ # name ファイル名 ############################ def initialize(name) # ファイルのオープン inn = open(name, "r") # 基本データ s = inn.gets().split(" ") @_n_city = Integer(s[1]) # 都市の数 @_max_try = Integer(s[3]) # 最大試行回数 @_sel = Integer(s[5]) # エッジの選択方法 # =0 最良のものを選択 # =1 最初のものを選択 @_neib = Integer(s[7]) # 近傍(2 or 3) s = inn.gets().split(" ") @_out_lvl = Integer(s[1]) # 出力レベル # =0 最終出力だけ # n>0 n回毎に出力(負の時はファイル) @_out_m = Integer(s[3]) # 出力方法 # =-1 出力しない # =0 すべてを出力 # =1 評価値だけを出力(最終結果だけはすべてを出力) s = inn.gets().split(" ") @_o_file = s[1] # 出力ファイル名 @_out_d = Integer(s[3]) # 表示間隔 # 都市の位置データ @_city = Array.new(@_n_city) for i1 in 0 ... @_n_city @_city[i1] = Array.new(2) s = inn.gets().split(" ") @_city[i1][0] = Integer(s[0]) @_city[i1][1] = Integer(s[1]) end # ファイルのクローズ inn.close() # 距離テーブルの作成 @_rg = Array.new(@_n_city) # 都市間の距離 for i1 in 0 ... @_n_city @_rg[i1] = Array.new(@_n_city) end for i1 in 0 ... @_n_city for i2 in i1+1 ... @_n_city x = @_city[i2][0] - @_city[i1][0] y = @_city[i2][1] - @_city[i1][1] @_rg[i1][i2] = (Math.sqrt(x * x + y * y)).round() end end for i1 in 0 ... @_n_city for i2 in 0 ... i1 @_rg[i1][i2] = @_rg[i2][i1] end end # 都市を訪れる順序(初期設定) @_seq = Array.new(@_n_city) # 都市を訪れる順序 @_seq_w1 = Array.new(@_n_city) # 都市を訪れる順序(ワーク) @_seq_w2 = Array.new(@_n_city) # 都市を訪れる順序(ワーク) for i1 in 0 ... @_n_city sw = 0 while sw == 0 ct = Integer(rand(0) * @_n_city) if ct >= @_n_city ct = @_n_city - 1 end @_seq[i1] = ct sw = 1 for i2 in 0 ... i1 if ct == @_seq[i2] sw = 0 break end end end end end ################# # 最適化の実行 ################# def Optimize() # 初期設定 n_tri = 0 max = Array.new(1) max[0] = kyori(@_n_city, @_seq, @_rg) if @_out_m >= 0 and @_out_lvl.abs() > 0 print("***試行回数 " + String(n_tri) + " 距離 " + String(-max[0]) + "\n") Output(@_out_lvl, n_tri, max[0]) end # 実行 sw = 1 for n_tri in 1 ... @_max_try+1 # 改善 sw = Change(max) # 出力 if @_out_d > 0 and n_tri%@_out_d == 0 print("***試行回数 " + String(n_tri) + " 距離 " + String(-max[0]) + "\n") end if @_out_m >= 0 and @_out_lvl.abs() > 0 if n_tri%@_out_lvl.abs() == 0 Output(@_out_lvl, n_tri, max[0]) end end if sw <= 0 break end end # 最終出力 if @_out_m >= 0 n_tri -= 1 k1 = @_out_m @_out_m = 0 print("***試行回数 " + String(n_tri) + " 距離 " + String(-max[0]) + "\n") Output(@_out_lvl, n_tri, max[0]) @_out_m = k1 end return n_tri end ############################### # 出力 # sw >= 0 出力先未定 # < 0 ファイル # n_tri 現在の試行回数 # r 距離の負値 ############################### def Output(sw, n_tri, r) k = 0 pr = -1 if sw >= 0 print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer($stdin.gets()) end if pr != 0 if pr > 0 out = $stdout $stdin.gets() else now = String(Time.now) out = open(@_o_file, "a") out.print("***試行回数 " + String(n_tri) + " 距離 " + String(-r) + " 時間 " + now + "\n") end if @_out_m == 0 for i1 in 0 ... @_n_city n = @_seq[i1] out.print(" " + String(n) + " " + String(@_city[n][0]) + " " + String(@_city[n][1]) + "\n") if pr > 0 k += 1 if k == pr $stdin.gets() k = 0 end end end end if pr <= 0 out.close() end end end ###################################### # エッジの入れ替え # r_m 距離の負値 # return =0 改善がなかった # =1 改善があった ###################################### def Change(r_m) ch = 0 sw = 0 max = r_m[0] n3 = Integer(rand(0) * (@_n_city - 2)) if n3 > @_n_city-3 n3 = @_n_city - 3 end # 2近傍 i1 = 0 while i1 <= @_n_city-3 and ch == 0 n1 = @_n_city - 1 if n3 == 0 n1 = @_n_city - 2 end i2 = n3 + 2 while i2 <= n1 and ch == 0 # 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 k2 = i2 + 1 if i2 == @_n_city-1 k2 = 0 end # 枝の入れ替え @_seq_w1[0] = @_seq[n3] k = 1 i3 = k1 while i3 > n3 @_seq_w1[k] = @_seq[i3] k += 1 i3 -= 1 end nn = k2 while nn != n3 @_seq_w1[k] = @_seq[nn] k += 1 nn += 1 if nn > @_n_city-1 nn = 0 end end # 評価 r = kyori(@_n_city, @_seq_w1, @_rg) if r > max max = r sw = 1 for i3 in 0 ... @_n_city @_seq_w2[i3] = @_seq_w1[i3] end if @_sel > 0 ch = 1 end end i2 += 1 end n3 += 1 if n3 > @_n_city-3 n3 = 0 end i1 += 1 end # 3近傍 if @_neib == 3 and ch == 0 i1 = 0 while i1 <= @_n_city-3 and ch == 0 n1 = @_n_city - 2 n2 = @_n_city - 1 i2 = n3 + 1 while i2 <= n1 and ch == 0 i3 = i2 + 1 while i3 <= n2 and ch == 0 # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 k2 = i3 + 1 if i3 == @_n_city-1 k2 = 0 end # 枝の入れ替えと評価 # 入れ替え(その1) @_seq_w1[0] = @_seq[n3] k = 1 i4 = i2 while i4 > n3 @_seq_w1[k] = @_seq[i4] k += 1 i4 -= 1 end i4 = k1 while i4 > i2 @_seq_w1[k] = @_seq[i4] k += 1 i4 -= 1 end nn = k2 while nn != n3 @_seq_w1[k] = @_seq[nn] k += 1 nn += 1 if nn > @_n_city-1 nn = 0 end end # 評価(その1) r = kyori(@_n_city, @_seq_w1, @_rg) if r > max max = r sw = 1 for i3 in 0 ... @_n_city @_seq_w2[i3] = @_seq_w1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その2) @_seq_w1[0] = @_seq[n3] k = 1 i4 = k1 while i4 > i2 @_seq_w1[k] = @_seq[i4] k += 1 i4 -= 1 end for i4 in n3+1 ... i2+1 @_seq_w1[k] = @_seq[i4] k += 1 end nn = k2 while nn != n3 @_seq_w1[k] = @_seq[nn] k += 1 nn += 1 if nn > @_n_city-1 nn = 0 end end # 評価(その2) r = kyori(@_n_city, @_seq_w1, @_rg) if r > max max = r sw = 1 for i3 in 0 ... @_n_city @_seq_w2[i3] = @_seq_w1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その3) @_seq_w1[0] = @_seq[n3] k = 1 for i4 in i2+1 ... k1+1 @_seq_w1[k] = @_seq[i4] k += 1 end i4 = i2 while i4 >n3 @_seq_w1[k] = @_seq[i4] k += 1 i4 -= 1 end nn = k2 while nn != n3 @_seq_w1[k] = @_seq[nn] k += 1 nn += 1 if nn > @_n_city-1 nn = 0 end end # 評価(その3) r = kyori(@_n_city, @_seq_w1, @_rg) if r > max max = r sw = 1 for i3 in 0 ... @_n_city @_seq_w2[i3] = @_seq_w1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その4) @_seq_w1[0] = @_seq[n3] k = 1 for i4 in i2+1 ... k1+1 @_seq_w1[k] = @_seq[i4] k += 1 end for i4 in n3+1 ... i2+1 @_seq_w1[k] = @_seq[i4] k += 1 end nn = k2 while nn != n3 @_seq_w1[k] = @_seq[nn] k += 1 nn += 1 if nn > @_n_city-1 nn = 0 end end # 評価(その4) r = kyori(@_n_city, @_seq_w1, @_rg) if r > max max = r sw = 1 for i3 in 0 ... @_n_city @_seq_w2[i3] = @_seq_w1[i3] end if @_sel > 0 ch = 1 end end i3 += 1 end i2 += 1 end n3 += 1 if n3 > @_n_city-3 n3 = 0 end i1 += 1 end end # 設定 if sw > 0 r_m[0] = max for i1 in 0 ... @_n_city @_seq[i1] = @_seq_w2[i1] end end return sw end end # 入力ミス if ARGV[0] == nil print("***error ファイル名を入力して下さい\n") # 入力OK else # データの数と入力データファイル名の入力 line = gets() n = Integer(line) # データの数 i_file = Array.new(n) for i1 in 0 ... n line = gets() a = line.split(" ") i_file[i1] = a[0] end # 実行 for i1 in 0 ... n print("\n+++++ケース " + String(i1+1) + "+++++\n") srand(1000 * i1 + 1234567); # 入力と初期設定 it = Iteration.new(i_file[i1]) # 最適化 it.Optimize() end end =begin ------------------ケーススタディデータ(data.txt)------ 3 data1.txt data1.txt data2.txt ------------------データファイル(data1.txt)------------ 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 ------------------データファイル(data2.txt)------------ 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 =end
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * from datetime import * ########################## # 距離の計算 # n_c : 都市の数 # p : 都市番号 # rg : 都市間の距離 # return : 距離(負) ########################## def kyori(n_c, p, rg) : r = 0 n1 = p[0] for i1 in range(1, n_c) : n2 = p[i1] r -= rg[n1][n2] n1 = n2 n2 = p[0] r -= rg[n1][n2] return r ######################### # クラスIterationの定義 ######################### class Iteration : ############################ # コンストラクタ # name : ファイル名 ############################ def __init__(self, name) : # ファイルのオープン inn = open(name, "r") # 基本データ s = inn.readline().split() self.n_city = int(s[1]) # 都市の数 self.max_try = int(s[3]) # 最大試行回数 self.sel = int(s[5]) # エッジの選択方法 # =0 : 最良のものを選択 # =1 : 最初のものを選択 self.neib = int(s[7]) # 近傍(2 or 3) s = inn.readline().split() self.out_lvl = int(s[1]) # 出力レベル # =0 : 最終出力だけ # n>0 : n回毎に出力(負の時はファイル) self.out_m = int(s[3]) # 出力方法 # =-1 : 出力しない # =0 : すべてを出力 # =1 : 評価値だけを出力(最終結果だけはすべてを出力) s = inn.readline().split() self.o_file = s[1] # 出力ファイル名 self.out_d = int(s[3]) # 表示間隔 # 都市の位置データ self.city = np.empty((self.n_city, 2), np.int) for i1 in range(0, self.n_city) : s = inn.readline().split() self.city[i1][0] = int(s[0]) self.city[i1][1] = int(s[1]) # ファイルのクローズ inn.close() # 距離テーブルの作成 self.rg = np.empty((self.n_city, self.n_city), np.int) # 都市間の距離 for i1 in range(0, self.n_city) : for i2 in range(i1+1, self.n_city) : x = self.city[i2][0] - self.city[i1][0] y = self.city[i2][1] - self.city[i1][1] self.rg[i1][i2] = int(sqrt(x * x + y * y) + 0.5) for i1 in range(0, self.n_city) : for i2 in range(0, i1) : self.rg[i1][i2] = self.rg[i2][i1] # 都市を訪れる順序(初期設定) self.seq = np.empty(self.n_city, np.int) # 都市を訪れる順序 self.seq_w1 = np.empty(self.n_city, np.int) # 都市を訪れる順序(ワーク) self.seq_w2 = np.empty(self.n_city, np.int) # 都市を訪れる順序(ワーク) for i1 in range(0, self.n_city) : sw = 0 while sw == 0 : ct = int(random() * self.n_city) if ct >= self.n_city : ct = self.n_city - 1 self.seq[i1] = ct sw = 1 for i2 in range(0, i1) : if ct == self.seq[i2] : sw = 0 break ################# # 最適化の実行 ################# def Optimize(self) : # 初期設定 n_tri = 0 max = np.empty(1, np.int) max[0] = kyori(self.n_city, self.seq, self.rg) if self.out_m >= 0 and abs(self.out_lvl) > 0 : print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) self.Output(self.out_lvl, n_tri, max[0]) # 実行 sw = 1 for n_tri in range(1, self.max_try+1) : # 改善 sw = self.Change(max) # 出力 if self.out_d > 0 and n_tri%self.out_d == 0 : print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) if self.out_m >= 0 and abs(self.out_lvl) > 0 : if n_tri%abs(self.out_lvl) == 0 : self.Output(self.out_lvl, n_tri, max[0]) if sw <= 0 : break # 最終出力 if self.out_m >= 0 : n_tri -= 1 k1 = self.out_m self.out_m = 0 print("***試行回数 " + str(n_tri) + " 距離 " + str(-max[0])) self.Output(self.out_lvl, n_tri, max[0]) self.out_m = k1 return n_tri ############################### # 出力 # sw : >= 0 : 出力先未定 # < 0 : ファイル # n_tri : 現在の試行回数 # r : 距離の負値 ############################### def Output(self, sw, n_tri, r) : k = 0 pr = -1 if sw >= 0 : print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ", end=" ") pr = int(input()) if pr != 0 : if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(self.o_file, "a") out.write("***試行回数 " + str(n_tri) + " 距離 " + str(-r) + " 時間 " + now + "\n") if self.out_m == 0 : for i1 in range(0, self.n_city) : n = self.seq[i1] out.write(" " + str(n) + " " + str(self.city[n][0]) + " " + str(self.city[n][1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr <= 0 : out.close() ###################################### # エッジの入れ替え # r_m : 距離の負値 # return : =0 : 改善がなかった # =1 : 改善があった ###################################### def Change(self, r_m) : ch = 0 sw = 0 max = r_m[0] n3 = int(random() * (self.n_city - 2)) if n3 > self.n_city-3 : n3 = self.n_city - 3 # 2近傍 i1 = 0 while i1 <= self.n_city-3 and ch == 0 : n1 = self.n_city - 1 if n3 == 0 : n1 = self.n_city - 2 i2 = n3 + 2 while i2 <= n1 and ch == 0 : # 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 k2 = i2 + 1 if i2 == self.n_city-1 : k2 = 0 # 枝の入れ替え self.seq_w1[0] = self.seq[n3] k = 1 for i3 in range(k1, n3, -1) : self.seq_w1[k] = self.seq[i3] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価 r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 i2 += 1 n3 += 1 if n3 > self.n_city-3 : n3 = 0 i1 += 1 # 3近傍 if self.neib == 3 and ch == 0 : i1 = 0 while i1 <= self.n_city-3 and ch == 0 : n1 = self.n_city - 2 n2 = self.n_city - 1 i2 = n3 + 1 while i2 <= n1 and ch == 0 : i3 = i2 + 1 while i3 <= n2 and ch == 0 : # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 k2 = i3 + 1 if i3 == self.n_city-1 : k2 = 0 # 枝の入れ替えと評価 # 入れ替え(その1) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2, n3, -1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(k1, i2, -1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その1) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その2) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(k1, i2, -1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その2) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その3) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(i2, n3, -1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その3) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その4) self.seq_w1[0] = self.seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.seq_w1[k] = self.seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.seq_w1[k] = self.seq[i4] k += 1 nn = k2 while nn != n3 : self.seq_w1[k] = self.seq[nn] k += 1 nn += 1 if nn > self.n_city-1 : nn = 0 # 評価(その4) r = kyori(self.n_city, self.seq_w1, self.rg) if r > max : max = r sw = 1 for i3 in range(0, self.n_city) : self.seq_w2[i3] = self.seq_w1[i3] if self.sel > 0 : ch = 1 i3 += 1 i2 += 1 n3 += 1 if n3 > self.n_city-3 : n3 = 0 i1 += 1 # 設定 if sw > 0 : r_m[0] = max for i1 in range(0, self.n_city) : self.seq[i1] = self.seq_w2[i1] return sw #################################### # 巡回セールスマン問題(反復改善法) # coded by Y.Suganuma #################################### # 入力ミス if len(sys.argv) <= 1 : print("***error ファイル名を入力して下さい") # 入力OK else : # データの数と入力データファイル名の入力 inn = open(sys.argv[1], "r") ss = inn.readline() n = int(ss) # データの数 i_file = [] for i1 in range(0, n) : i_file.append(inn.readline().strip(" \n")) inn.close() # 実行 for i1 in range(0, n) : print("\n+++++ケース " + str(i1+1) + "+++++") seed(1000 * i1 + 1234567); # 入力と初期設定 it = Iteration (i_file[i1]) # 最適化 it.Optimize() """ ------------------ケーススタディデータ(data.txt)------ 3 data1.txt data1.txt data2.txt ------------------データファイル(data1.txt)------------ 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 ------------------データファイル(data2.txt)------------ 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 """
/****************************/ /* 巡回セールスマン問題 */ /* 反復改善法 */ /* coded by Y.Suganuma */ /****************************/ using System; using System.IO; /*************************/ /* クラスIterationの定義 */ /*************************/ class Iteration { int max_try; // 最大試行回数 int neib; // 近傍(2 or 3) int out_d; // 表示間隔 int [][] rg; // 都市間の距離 int [] seq_w1; // 都市を訪れる順序(ワーク) int [] seq_w2; // 都市を訪れる順序(ワーク) int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n回毎に出力(負の時はファイル) int out_m; // 出力方法 // =-1 : 出力しない // =0 : すべてを出力 // =1 : 評価値だけを出力(最終結果だけはすべてを出力) int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 String o_file; // 出力ファイル名 Random rn; // 乱数 int [][] city; //都市の位置データ int n_city; // 都市の数 int n_tri; // 試行回数 int [] seq; // 都市を訪れる順序 int range; // 現在の評価値 /****************************/ /* コンストラクタ */ /* seed : 乱数の初期値 */ /* name : ファイル名 */ /****************************/ public Iteration (int seed, String name) { n_tri = 0; string[] lines = File.ReadAllLines(name); char[] charSep = new char[] {' '}; // 乱数の初期設定 rn = new Random(seed); // 基本データ // 1行目 string[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); n_city = int.Parse(str[1]); max_try = int.Parse(str[3]); sel = int.Parse(str[5]); neib = int.Parse(str[7]); // 2行目 str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); out_lvl = int.Parse(str[1]); out_m = int.Parse(str[3]); // 3行目 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); o_file = str[1]; out_d = int.Parse(str[3]); // 都市の位置データ city = new int [n_city][]; for (int i1 = 0; i1 < n_city; i1++) { city[i1] = new int [2]; str = lines[i1+3].Split(charSep, StringSplitOptions.RemoveEmptyEntries); city[i1][0] = int.Parse(str[0]); city[i1][1] = int.Parse(str[1]); } // 距離テーブルの作成 rg = new int [n_city][]; for (int i1 = 0; i1 < n_city; i1++) { rg[i1] = new int [n_city]; for (int i2 = i1+1; i2 < n_city; i2++) { double x = city[i2][0] - city[i1][0]; double y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(Math.Sqrt(x * x + y * y) + 0.5); } } for (int i1 = 1; i1 < n_city; i1++) { for (int i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } // 都市を訪れる順序(初期設定) seq = new int [n_city]; seq_w1 = new int [n_city]; seq_w2 = new int [n_city]; for (int i1 = 0; i1 < n_city; i1++) { int sw = 0; while (sw == 0) { int ct = (int)(rn.NextDouble() * n_city); if (ct >= n_city) ct = n_city - 1; seq[i1] = ct; sw = 1; for (int i2 = 0; i2 < i1 && sw > 0; i2++) { if (ct == seq[i2]) sw = 0; } } } } /****************/ /* 最適化の実行 */ /****************/ public int Optimize () { // 初期設定 range = kyori(n_city, seq, rg); // 初期状態の出力(文字) if (out_m >= 0 && Math.Abs(out_lvl) > 0) { Console.WriteLine("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); } // 実行 int sw = 1; for (n_tri = 1; n_tri <= max_try && sw > 0; n_tri++) { // 改善 sw = Change(); // 出力(文字) if (out_d > 0 && n_tri%out_d == 0) Console.WriteLine("***試行回数 " + n_tri + " 距離 " + (-range)); if (out_m >= 0 && Math.Abs(out_lvl) > 0) { if (n_tri%Math.Abs(out_lvl) == 0) Output(out_lvl); } } // 最終出力(文字) if (out_m >= 0) { n_tri--; int k1 = out_m; out_m = 0; Console.WriteLine("***試行回数 " + n_tri + " 距離 " + (-range)); Output(out_lvl); out_m = k1; } return n_tri; } /*******************************/ /* 出力 */ /* sw : >= 0 : 出力先未定 */ /* < 0 : ファイル */ /*******************************/ void Output(int sw) { int pr = -1; if (sw >= 0) { Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = int.Parse(Console.ReadLine()); } if (pr != 0) { StreamWriter OUT = new StreamWriter(o_file, true); if (pr < 0) { DateTime now = DateTime.Now; // 現在時刻の獲得 OUT.WriteLine("***試行回数 " + n_tri + " 距離 " + (-range) + " 時間 " + now); } if (out_m == 0) { int k = 0; for (int i1 = 0; i1 < n_city; i1++) { int n = seq[i1]; if (pr < 0) OUT.WriteLine(" " + n + " " + city[n][0] + " " + city[n][1]); else Console.WriteLine(" " + n + " " + city[n][0] + " " + city[n][1]); if (pr > 0) { k++; if (k == pr) { Console.ReadLine(); k = 0; } } } } OUT.Close(); } } /**************************************/ /* エッジの入れ替え */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int Change() { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = range; n3 = (int)(rn.NextDouble() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え seq_w1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { seq_w1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その2) seq_w1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その3) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その4) seq_w1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { seq_w1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { seq_w1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { seq_w1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = kyori(n_city, seq_w1, rg); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) seq_w2[i3] = seq_w1[i3]; if (sel > 0) ch = 1; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { range = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = seq_w2[i1]; } return sw; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* rg : 都市間の距離 */ /* return : 距離(負) */ /*********************************/ static int kyori(int n_c, int [] p, int [][] rg) { int n1 = p[0]; int n2; int range = 0; for (int i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } } /****************/ /* main program */ /****************/ class Program { static void Main(String[] args) { // 入力ミス if (args.Length == 0) Console.WriteLine("***error ケーススタディファイル名を入力して下さい"); // 入力OK else { // 入力データファイル名の入力 String[] lines = File.ReadAllLines(args[0]); int n = int.Parse(lines[0]); // 問題の数 String[] i_file = new String [n]; for (int i1 = 0; i1 < n; i1++) i_file[i1] = lines[i1+1]; // 実行(乱数の初期値を変える) for (int i1 = 0; i1 < n; i1++) { Console.WriteLine(); Console.WriteLine("+++++ケース " + (i1+1) + "+++++"); // 入力と初期設定 Iteration it = new Iteration (1000 * i1 + 1234567, i_file[i1]); // 最適化 it.Optimize(); } } } } //------------------------ケーススタディデータ(data.txt)------ /* 3 data1.txt data1.txt data2.txt */ //---------------------データファイル(data1.txt)------------ /* 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------データファイル(data2.txt)------------ /* 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 */
'**************************' ' 巡回セールスマン問題 ' ' 反復改善法 ' ' coded by Y.Suganuma ' '**************************' Imports System.IO Imports System.Text.RegularExpressions Module Test Sub Main(args() As String) ' 入力ミス If args.Length = 0 Console.WriteLine("***error ケーススタディファイル名を入力して下さい") ' 入力OK Else ' 入力データファイル名の入力 Dim inp As StreamReader = New StreamReader(args(0)) Dim n As Integer = Integer.Parse(inp.ReadLine()) ' 問題の数 Dim i_file(n) As String For i1 As Integer = 0 To n-1 i_file(i1) = inp.ReadLine() Next inp.Close() ' 実行(乱数の初期値を変える) For i1 As Integer = 0 To n-1 Console.WriteLine() Console.WriteLine("+++++ケース " & (i1+1) & "+++++") ' 入力と初期設定 Dim it As Iteration = new Iteration (1000 * i1 + 1234567, i_file(i1)) ' 最適化 it.Optimize() Next End If End Sub '*******************************' ' 距離の計算 ' ' n_c : 都市の数 ' ' p : 都市番号 ' ' rg : 都市間の距離 ' ' return : 距離 ' '*******************************' Function kyori(n_c As Integer, p() As Integer, rg(,) As Integer) Dim range As Double = 0 Dim n1 As Integer = p(0) Dim n2 As Integer For i1 As Integer = 1 To n_c-1 n2 = p(i1) range -= rg(n1,n2) n1 = n2 Next n2 = p(0) range -= rg(n1,n2) Return range End Function '***********************' ' クラスIterationの定義 ' '***********************' Class Iteration Private max_try As Integer ' 最大試行回数 Private neib As Integer ' 近傍(2 or 3) Private out_d As Integer ' 表示間隔 Private rg(,) As Integer ' 都市間の距離 Private seq_w1() As Integer ' 都市を訪れる順序(ワーク) Private seq_w2() As Integer ' 都市を訪れる順序(ワーク) Private out_lvl As Integer ' 出力レベル ' =0 : 最終出力だけ ' n>0 : n回毎に出力(負の時はファイル) Private out_m As Integer ' 出力方法 ' =-1 : 出力しない ' =0 : すべてを出力 ' =1 : 評価値だけを出力(最終結果だけはすべてを出力) Private sel As Integer ' エッジの選択方法 ' =0 : 最良のものを選択 ' =1 : 最初のものを選択 Private o_file As String ' 出力ファイル名 Private rn As Random ' 乱数 Private city(,) As Integer '都市の位置データ Private n_city As Integer ' 都市の数 Private n_tri As Integer ' 試行回数 Public seq() As Integer ' 都市を訪れる順序 Private range As Integer ' 現在の評価値 '**************************' ' コンストラクタ ' ' seed : 乱数の初期値 ' ' name : ファイル名 ' '**************************' Public Sub New (seed As Integer, name As String) n_tri = 0 Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name) ' 乱数の初期設定 rn = new Random(seed) ' 基本データ ' 1行目 Dim str() As String = MS.Split(inp.ReadLine().Trim()) n_city = Integer.Parse(str(1)) max_try = Integer.Parse(str(3)) sel = Integer.Parse(str(5)) neib = Integer.Parse(str(7)) ' 2行目 str = MS.Split(inp.ReadLine().Trim()) out_lvl = Integer.Parse(str(1)) out_m = Integer.Parse(str(3)) ' 3行目 str = MS.Split(inp.ReadLine().Trim()) o_file = str(1) out_d = Integer.Parse(str(3)) ' 都市の位置データ ReDim city(n_city, 2) For i1 As Integer = 0 To n_city-1 str = MS.Split(inp.ReadLine().Trim()) city(i1,0) = Integer.Parse(str(0)) city(i1,1) = Integer.Parse(str(1)) Next inp.Close() ' 距離テーブルの作成 ReDim rg(n_city, n_city) For i1 As Integer = 0 To n_city-1 For i2 As Integer = i1+1 To n_city-1 Dim x As Double = city(i2,0) - city(i1,0) Dim y As Double = city(i2,1) - city(i1,1) rg(i1,i2) = Math.Floor(Math.Sqrt(x * x + y * y) + 0.5) Next Next For i1 As Integer = 1 To n_city-1 For i2 As Integer = 0 To i1-1 rg(i1,i2) = rg(i2,i1) Next Next ' 都市を訪れる順序(初期設定) ReDim seq(n_city) ReDim seq_w1(n_city) ReDim seq_w2(n_city) For i1 As Integer = 0 To n_city-1 Dim sw As Integer = 0 Do While sw = 0 Dim ct As Integer = Math.Floor(rn.NextDouble() * n_city) If ct >= n_city ct = n_city - 1 End If seq(i1) = ct sw = 1 Dim i2 As Integer = 0 Do While i2 < i1 and sw > 0 If ct = seq(i2) sw = 0 End If i2 += 1 Loop Loop Next End Sub '**************' ' 最適化の実行 ' '**************' Public Function Optimize () ' 初期設定 range = kyori(n_city, seq, rg) ' 初期状態の出力(文字) If out_m >= 0 and Math.Abs(out_lvl) > 0 Console.WriteLine("***試行回数 " & n_tri & " 距離 " & (-range)) Output(out_lvl) End If ' 実行 Dim sw As Integer = 1 n_tri = 1 Do While n_tri <= max_try and sw > 0 ' 改善 sw = Change() ' 出力(文字) If out_d > 0 If (n_tri Mod out_d) = 0 Console.WriteLine("***試行回数 " + n_tri + " 距離 " + (-range)) End If If out_m >= 0 If Math.Abs(out_lvl) > 0 If (n_tri Mod Math.Abs(out_lvl)) = 0 Output(out_lvl) End If End If End If End If n_tri += 1 Loop ' 最終出力(文字) If out_m >= 0 n_tri -= 1 Dim k1 As Integer = out_m out_m = 0 Console.WriteLine("***試行回数 " & n_tri & " 距離 " & (-range)) Output(out_lvl) out_m = k1 End If Return n_tri End Function '*****************************' ' 出力 ' ' sw : >= 0 : 出力先未定 ' ' < 0 : ファイル ' '*****************************' Sub Output(sw As Integer) Dim pr As Integer = -1 If sw >= 0 Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer.Parse(Console.ReadLine()) End If If pr <> 0 Dim OUT As StreamWriter = new StreamWriter(o_file, true) If pr < 0 Dim now1 As DateTime = DateTime.Now ' 現在時刻の獲得 OUT.WriteLine("***試行回数 " & n_tri & " 距離 " & (-range) & " 時間 " & now1) End If If out_m = 0 Dim k As Integer = 0 For i1 As Integer = 0 To n_city-1 Dim n As Integer = seq(i1) If pr < 0 OUT.WriteLine(" " & n & " " & city(n,0) & " " & city(n,1)) Else Console.WriteLine(" " & n & " " & city(n,0) & " " & city(n,1)) End If If pr > 0 k += 1 If k = pr Console.ReadLine() k = 0 End If End If Next End If OUT.Close() End If End Sub '************************************' ' エッジの入れ替え ' ' return : =0 : 改善がなかった ' ' =1 : 改善があった ' '************************************' Function Change() Dim ch As Integer = 0 Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k As Integer Dim k1 As Integer Dim k2 As Integer Dim max As Integer Dim n1 As Integer Dim n2 As Integer Dim n3 As Integer Dim nn As Integer Dim r As Integer Dim sw As Integer = 0 max = range n3 = Math.Floor(rn.NextDouble() * (n_city - 2)) If n3 > n_city-3 n3 = n_city - 3 End If ' 2近傍 i1 = 0 Do While i1 <= n_city-3 and ch = 0 If n3 = 0 n1 = n_city - 2 Else n1 = n_city - 1 End If i2 = n3 + 2 Do While i2 <= n1 and ch = 0 ' 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 If i2 = n_city-1 k2 = 0 Else k2 = i2 + 1 End If ' 枝の入れ替え seq_w1(0) = seq(n3) k = 1 For i3 = k1 To n3+1 Step -1 seq_w1(k) = seq(i3) k += 1 Next nn = k2 Do While nn <> n3 seq_w1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価 r = kyori(n_city, seq_w1, rg) If r > max max = r sw = 1 For i3 = 0 To n_city-1 seq_w2(i3) = seq_w1(i3) Next If sel > 0 ch = 1 End If End If i2 += 1 Loop n3 += 1 If n3 > n_city-3 n3 = 0 End If i1 += 1 Loop ' 3近傍 If neib = 3 and ch = 0 i1 = 0 Do While i1 <= n_city-3 and ch = 0 n1 = n_city - 2 n2 = n_city - 1 i2 = n3 + 1 Do While i2 <= n1 and ch = 0 i3 = i2 + 1 Do While i3 <= n2 and ch = 0 ' 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 If i3 = n_city-1 k2 = 0 Else k2 = i3 + 1 End If ' 枝の入れ替えと評価 ' 入れ替え(その1) seq_w1(0) = seq(n3) k = 1 For i4 = i2 To n3+1 Step -1 seq_w1(k) = seq(i4) k += 1 Next For i4 = k1 To i2+1 Step -1 seq_w1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 seq_w1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その1) r = kyori(n_city, seq_w1, rg) If r > max max = r sw = 1 For i3 = 0 To n_city-1 seq_w2(i3) = seq_w1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その2) seq_w1(0) = seq(n3) k = 1 For i4 = k1 To i2+1 Step -1 seq_w1(k) = seq(i4) k += 1 Next For i4 = n3+1 To i2 seq_w1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 seq_w1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その2) r = kyori(n_city, seq_w1, rg) If r > max max = r sw = 1 For i3 = 0 To n_city-1 seq_w2(i3) = seq_w1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その3) seq_w1(0) = seq(n3) k = 1 For i4 = i2+1 To k1 seq_w1(k) = seq(i4) k += 1 Next For i4 = i2 To n3+1 Step -1 seq_w1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 seq_w1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その3) r = kyori(n_city, seq_w1, rg) If r > max max = r sw = 1 For i3 = 0 To n_city-1 seq_w2(i3) = seq_w1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その4) seq_w1(0) = seq(n3) k = 1 For i4 = i2+1 To k1 seq_w1(k) = seq(i4) k += 1 Next For i4 = n3+1 To i2 seq_w1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 seq_w1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その4) r = kyori(n_city, seq_w1, rg) If r > max max = r sw = 1 For i3 = 0 To n_city-1 seq_w2(i3) = seq_w1(i3) Next If sel > 0 ch = 1 End If End If i3 += 1 Loop i2 += 1 Loop n3 += 1 If n3 > n_city-3 n3 = 0 End If i1 += 1 Loop End If ' 設定 If sw > 0 range = max For i1 = 0 To n_city-1 seq(i1) = seq_w2(i1) Next End If Return sw End Function End Class End Module //------------------------ケーススタディデータ(data.txt)------ /* 3 data1.txt data1.txt data2.txt */ //---------------------データファイル(data1.txt)------------ /* 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------データファイル(data2.txt)------------ /* 都市の数 50 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 out1.txt 表示間隔 0 86 27 82 16 29 37 27 1 90 88 40 92 87 53 24 99 11 80 61 8 30 93 4 81 86 90 84 52 96 45 4 34 53 6 45 12 23 97 61 46 49 16 82 74 48 36 13 5 12 6 33 26 8 50 98 98 79 65 36 56 42 25 52 12 88 79 27 51 86 51 14 35 77 37 44 0 78 13 21 55 82 26 25 88 55 0 10 59 41 33 7 4 56 99 19 34 92 46 27 35 */
情報学部 | 菅沼ホーム | 目次 | 索引 |