データ例とプログラム
------------------------ケーススタディデータ------ 問題の数 2 問題 data/pr439.tsp 乱数の数 10 乱数 1 乱数 12 乱数 123 乱数 1234 乱数 12345 乱数 54321 乱数 5432 乱数 543 乱数 54 乱数 5 問題 data/kroA100.tsp 乱数の数 10 乱数 1 乱数 12 乱数 123 乱数 1234 乱数 12345 乱数 54321 乱数 5432 乱数 543 乱数 54 乱数 5 ------------------------データファイル------------ 都市の数 439 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 整数 1 出力(0:ディスプレイ,1:ファイル) -1 出力ファイル名 result/pr439 分割数 X 4 Y 3 最大試行回数 1000 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 3 都市番号 0 図の大きさ(幅,高さ) 1000 750 7125 11300 7225 11050 ・・・・・ 1775 5375 2075 6475 ------------------------クラスPartition----------- /*************************/ /* クラスPartitionの定義 */ /*************************/ import java.io.*; import java.util.Random; import java.util.Date; import java.util.StringTokenizer; class Partition { private float [][] rg; // 都市間の距離 private float [] p_x; // x軸の分割点 private float [] p_y; // y軸の分割点 private int fix; // =1 : 近傍を固定 // =0 : 近傍を可変 private int max_try; // 最大試行回数 private int [] seq_w1; // 作業領域 private int [] seq_w2; // 作業領域 private int neib; // 近傍(2 or 3) int seisu; // 位置データの表現方法 // =1 : 整数 // =-1 : 実数(距離を整数計算) // =-2 : 実数(距離を実数計算) private int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 private String i_file; // 入力ファイル名 private Win_pt wn; // Win_itオブジェクト private Random rn; // 乱数 float [][] city; //都市の位置データ float [][] city_i; //都市の位置データ(作業領域) int Max; // 最適経路の長さ int n_city; // 都市の数 int [][] n_seq; // 各領域の都市数 int [][] n_seq1; // 各領域の都市数(ワーク) int n_p_x; // x軸方向の分割数 int n_p_y; // y軸方向の分割数 int out_m; // 出力方法 // =-1 : ディスプレイ(経路長だけ) // =0 : ディスプレイ // =1 : ファイル // =2 : ファイル(経路長だけ) int range; // 現在の評価値 int seed; // 乱数の初期値 int [][][] seq; // 経路 int [][][] seq1; // 経路(ワーク) int [][] state; // 領域結合用ワーク int display; // 画面表示 // =0 : 画面表示を行わない // =1 : 結果だけを表示 // =2 : 初期状態と結果を表示 // =3 : 1領域の最適化終了毎に表示 String o_file; // 出力ファイル名 /**************************/ /* コンストラクタ */ /* name : ファイル名 */ /**************************/ Partition(String name) throws IOException, FileNotFoundException { double x, y; float max_x, max_y, min_x, min_y, s_x, s_y; int i1, i2, i3, max = 0, n; String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name)); // 基本データ i_file = name; line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); n_city = Integer.parseInt(dt.nextToken()); dt.nextToken(); sel = Integer.parseInt(dt.nextToken()); dt.nextToken(); neib = Integer.parseInt(dt.nextToken()); dt.nextToken(); seisu = Integer.parseInt(dt.nextToken()); if (neib < 0) { neib = -neib; fix = 0; } else fix = 1; line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); out_m = Integer.parseInt(dt.nextToken()); dt.nextToken(); o_file = dt.nextToken(); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); dt.nextToken(); n_p_x = Integer.parseInt(dt.nextToken()); dt.nextToken(); n_p_y = Integer.parseInt(dt.nextToken()); dt.nextToken(); max_try = 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 float [n_city][2]; for (i1 = 0; i1 < n_city; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); city[i1][0] = Float.parseFloat(dt.nextToken()); city[i1][1] = Float.parseFloat(dt.nextToken()); } // ファイルのクローズ in.close(); // 距離テーブルの作成 rg = new float [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] = (float)Math.sqrt(x * x + y * y); if (seisu > -2) rg[i1][i2] = (int)(rg[i1][i2] + 0.5); } } for (i1 = 1; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } // 作業領域 state = new int [n_p_y][n_p_x]; n_seq = new int [n_p_y][n_p_x]; n_seq1 = new int [n_p_y][n_p_x]; seq = new int [n_p_y][n_p_x][n_city]; seq1 = new int [n_p_y][n_p_x][n_city]; seq_w1 = new int [n_city]; seq_w2 = new int [n_city]; p_x = new float [n_p_x]; p_y = new float [n_p_y]; // 都市の分割 for (i1 = 0; i1 < n_city; i1++) seq_w1[i1] = 0; min_x = city[0][0]; max_x = city[0][0]; min_y = city[0][1]; max_y = city[0][1]; for (i1 = 1; i1 < n_city; i1++) { if (city[i1][0] < min_x) min_x = city[i1][0]; else { if (city[i1][0] > max_x) max_x = city[i1][0]; } if (city[i1][1] < min_y) min_y = city[i1][1]; else { if (city[i1][1] > max_y) max_y = city[i1][1]; } } s_x = (max_x - min_x) / n_p_x; p_x[0] = min_x + s_x; p_x[n_p_x-1] = max_x; for (i1 = 1; i1 < n_p_x-1; i1++) p_x[i1] = p_x[0] + i1 * s_x; s_y = (max_y - min_y) / n_p_y; p_y[0] = min_y + s_y; p_y[n_p_y-1] = max_y; for (i1 = 1; i1 < n_p_y-1; i1++) p_y[i1] = p_y[0] + i1 * s_y; for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) { n = 0; for (i3 = 0; i3 < n_city; i3++) { if (seq_w1[i3] == 0) { if (city[i3][0] <= p_x[i2] && city[i3][1] <= p_y[i1]) { seq_w1[i3] = 1; seq_w2[n] = i3; n++; } } } n_seq1[i1][i2] = n; if (n > 0) { for (i3 = 0; i3 < n; i3++) seq1[i1][i2][i3] = seq_w2[i3]; if (n > max) max = n; } } } for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) state[i1][i2] = (n_seq1[i1][i2] > 0) ? 0 : 1; } // 作業領域 System.out.println("max " + max); city_i = new float [max][2]; // Windowの生成 if (display > 0) wn = new Win_pt (this, font, width, height); } /******************************/ /* 最適化の実行 */ /* seed_i : 乱数の初期値 */ /******************************/ void Optimize(int seed_i) throws IOException, FileNotFoundException { int i1, i2, i3, k, max, nb, r; Iteration it; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 乱数の初期設定 seed = seed_i; rn = new Random (seed); for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) { n_seq[i1][i2] = n_seq1[i1][i2]; state[i1][i2] = (n_seq1[i1][i2] > 0) ? 0 : 1; for (i3 = 0; i3 < n_seq1[i1][i2]; i3++) seq[i1][i2][i3] = seq1[i1][i2][i3]; } } // 初期状態の出力(図) if (display >= 2) { wn.Draw(0, -1, -1); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } // 分割数と開始時間の出力(ファイルへ出力する場合) if (out_m > 0) Output(0); // 分割毎の最適化 for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) { if (n_seq[i1][i2] > 3) { // 近傍の大きさ nb = (n_seq[i1][i2] > 3) ? neib : 2; // 都市位置データの設定 for (i3 = 0; i3 < n_seq[i1][i2]; i3++) { k = seq[i1][i2][i3]; city_i[i3][0] = city[k][0]; city_i[i3][1] = city[k][1]; } // 最適化 it = new Iteration (n_seq[i1][i2], max_try, seisu, sel, nb, fix, 0, -1, 0, o_file, city_i, 0, rn); max = it.Optimize(); // 結果の保存 for (i3 = 0; i3 < n_seq[i1][i2]; i3++) { k = it.seq[i3]; seq_w1[i3] = seq[i1][i2][k]; } for (i3 = 0; i3 < n_seq[i1][i2]; i3++) seq[i1][i2][i3] = seq_w1[i3]; // 出力(文字) r = (seisu > -2) ? (int)Iteration.kyori(n_seq[i1][i2], seq[i1][i2], rg) : (int)(Iteration.kyori(n_seq[i1][i2], seq[i1][i2], rg) + 0.5); System.out.print(" y " + (i1+1) + " x " + (i2+1) + " n_city " + n_seq[i1][i2] + " range " + r + " (trial " + max + ")\n"); // 区分毎最適化結果の出力(図) if (display == 3) { wn.Draw(0, i1, i2); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } } } } // 経路の接続 range = Connect(); Max = range; // 出力(図) if (display > 0) { wn.Draw(1, -1, -1); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } // 出力(文字) Output(n_city); } /***********************/ /* 出力 */ /* n_c : 都市の数 */ /***********************/ void Output(int n_c) throws IOException, FileNotFoundException { int i1, k = 0, n; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (out_m <= 0) { out = System.out; out.println("距離 " + range); in.readLine(); } else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(o_file, true)); if (n_c > 0) { System.out.println("距離 " + range); out.println(" 距離 " + range + " 時間 " + now); } else out.println("問題 " + i_file + " 乱数 " + seed + " 分割 " + n_p_x + " " + n_p_y + " 時間 " + now); } if (n_c > 0 && (out_m == 0 || out_m == 1)) { for (i1 = 0; i1 < n_c; i1++) { n = seq_w1[i1]; if (seisu > 0) out.println(" " + n + " " + (int)city[n][0] + " " + (int)city[n][1]); else out.println(" " + n + " " + city[n][0] + " " + city[n][1]); if (out_m == 0) { k++; if (k == 10) { in.readLine(); k = 0; } } } } if (out_m > 0) out.close(); } /************************/ /* 分割された領域の接続 */ /************************/ int Connect() throws IOException { double wd, wd1, wa1, wa2, min = 0; int i1, i2, i3, i4, k, k1 = 0, k2 = 0, k3 = 0, k4 = 0, min_c = 0, n, r, r1 = 0, r2 = 0, r3 = 0, r4 = 0, s1 = 0, s2 = 0, sw = 1; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); /* 領域が1つの場合 */ if (n_p_x == 1 && n_p_y == 1) { for (i1 = 0; i1 < n_seq[0][0]; i1++) seq_w1[i1] = seq[0][0][i1]; } /* 領域が複数の場合 */ else { while (sw > 0) { // 最小節点領域 min_c = n_city; sw = 0; for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) { if (state[i1][i2] == 0 && n_seq[i1][i2] < min_c) { sw = 1; r1 = i1; r2 = i2; min_c = n_seq[i1][i2]; } } } // 結合する対象領域の決定 if (sw > 0) { sw = 0; for (i1 = 0; i1 < n_p_y; i1++) { for (i2 = 0; i2 < n_p_x; i2++) { if (state[i1][i2] == 0 && (i1 != r1 || i2 !=r2)) { // 節点の数>2 if (n_seq[r1][r2] > 1) { for (i3 = 0; i3 < n_seq[r1][r2]; i3++) { k1 = seq[r1][r2][i3]; k2 = (i3 == n_seq[r1][r2]-1) ? seq[r1][r2][0] : seq[r1][r2][i3+1]; wd1 = rg[k1][k2]; for (i4 = 0; i4 < n_seq[i1][i2]; i4++) { k3 = seq[i1][i2][i4]; k4 = (i4 == n_seq[i1][i2]-1) ? seq[i1][i2][0] : seq[i1][i2][i4+1]; wd = wd1 + rg[k3][k4]; wa1 = rg[k1][k3] + rg[k2][k4]; wa2 = rg[k1][k4] + rg[k2][k3]; if (sw == 0 || wa1-wd < min) { min = wa1 - wd; r3 = i1; r4 = i2; s1 = (i3 == n_seq[r1][r2]-1) ? 0 : i3 + 1; s2 = (i4 == n_seq[i1][i2]-1) ? 0 : i4 + 1; sw = -1; } if (sw == 0 || wa2-wd < min) { min = wa2 - wd; r3 = i1; r4 = i2; s1 = i3; s2 = (i4 == n_seq[i1][i2]-1) ? 0 : i4 + 1; sw = 1; } } } } // 節点の数=1 else { k1 = seq[r1][r2][0]; if (n_seq[i1][i2] > 1) { for (i4 = 0; i4 < n_seq[i1][i2]; i4++) { k3 = seq[i1][i2][i4]; k4 = (i4 == n_seq[i1][i2]-1) ? seq[i1][i2][0] : seq[i1][i2][i4+1]; wd = rg[k3][k4]; wa1 = rg[k1][k3] + rg[k1][k4]; if (sw == 0 || wa1-wd < min) { min = wa1 - wd; r3 = i1; r4 = i2; s1 = 0; s2 = (i4 == n_seq[i1][i2]-1) ? 0 : i4 + 1; sw = 1; } } } else { k3 = seq[i1][i2][0]; wa1 = rg[k1][k3]; if (sw == 0 || wa1 < min) { min = wa1; r3 = i1; r4 = i2; s1 = 0; s2 = 0; sw = 1; } } } } } } // 領域の結合 seq_w1[0] = seq[r1][r2][s1]; k = 1; n = s2; for (i1 = 0; i1 < n_seq[r3][r4]; i1++) { seq_w1[k] = seq[r3][r4][n]; k++; n++; if (n > n_seq[r3][r4]-1) n = 0; } if (sw > 0) { n = s1 + 1; for (i1 = 0; i1 < n_seq[r1][r2]-1; i1++) { if (n > n_seq[r1][r2]-1) n = 0; seq_w1[k] = seq[r1][r2][n]; k++; n++; } } else { n = s1 - 1; for (i1 = 0; i1 < n_seq[r1][r2]-1; i1++) { if (n < 0) n = n_seq[r1][r2] - 1; seq_w1[k] = seq[r1][r2][n]; k++; n--; } } // 状態の変更 n_seq[r1][r2] += n_seq[r3][r4]; state[r3][r4] = 1; for (i1 = 0; i1 < n_seq[r1][r2]; i1++) seq[r1][r2][i1] = seq_w1[i1]; sw = 1; // 結果の図示 if (display == 3) { wn.Draw(0, r1, r2); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } } } } r = (seisu > -2) ? (int)Iteration.kyori(n_city, seq_w1, rg) : (int)(Iteration.kyori(n_city, seq_w1, rg) + 0.5); return r; } } ------------------------クラスIteration----------- /*************************/ /* クラスIterationの定義 */ /*************************/ import java.io.*; import java.util.Random; import java.util.Date; class Iteration { private float [][] rg; // 都市間の距離 private int fix; // =1 : 近傍を固定 // =0 : 近傍を可変 private int max_try; // 最大試行回数 private int neib; // 近傍(2 or 3) private int out_d; // 表示間隔 private int [] seq_w1; // 都市を訪れる順序(ワーク) private int [] seq_w2; // 都市を訪れる順序(ワーク) private int [] seq_w3; // 都市を訪れる順序(ワーク) private int [] seq_w4; // 都市を訪れる順序(ワーク) private int [] seq_w5; // 都市を訪れる順序(ワーク) private int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) private int out_m; // 出力方法 // =-1 : 出力しない // =0 : すべてを出力 // =1 : 評価値だけを出力(最終結果だけはすべてを出力) int seisu; // 位置データの表現方法 // =1 : 整数 // =-1 : 実数(距離を整数計算) // =-2 : 実数(距離を実数計算) private int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 private String o_file; // 出力ファイル名 private Win_it wn; // Win_itオブジェクト private Random rn; // 乱数 double range; // 現在の評価値 float [][] city; //都市の位置データ int n_city; // 都市の数 int n_tri; // 試行回数 int [] seq; // 都市を訪れる順序 int n_eg; // 交換した枝の数 int [] eg; // 交換した枝 int display; // 画面表示 // =0 : 画面表示を行わない // =1 : 結果だけを表示 // =2 : 初期状態と結果を表示 // =3 : ワンステップ毎表示 /**********************************/ /* コンストラクタ */ /* n_city_i : 都市の数 */ /* max_try_i : 最大試行回数 */ /* sei_i : 整数 or 実数 */ /* sel_i : エッジの選択方法 */ /* neib_i : 近傍(2 or 3) */ /* fix_i : 近傍の扱い方 */ /* out_lvl_i : 出力レベル */ /* out_m_i : 出力方法 */ /* out_d_i : 表示間隔 */ /* o_file_i : 出力ファイル名 */ /* city_i : 都市の位置データ */ /* display_i : 画面表示 */ /* rn_i : 乱数 */ /**********************************/ Iteration (int n_city_i, int max_tri_i, int sei_i, int sel_i, int neib_i, int fix_i, int out_lvl_i, int out_m_i, int out_d_i, String o_file_i, float [][] city_i, int display_i, Random rn_i) { double x, y; int ct, i1, i2, sw; // 値の設定 n_city = n_city_i; max_try = max_tri_i; seisu = sei_i; sel = sel_i; neib = neib_i; fix = fix_i; out_lvl = out_lvl_i; out_m = out_m_i; out_d = out_d_i; o_file = o_file_i; display = display_i; rn = rn_i; n_tri = 0; n_eg = 0; eg = new int [6]; // 都市の位置データ city = new float [n_city][2]; for (i1 = 0; i1 < n_city; i1++) { city[i1][0] = city_i[i1][0]; city[i1][1] = city_i[i1][1]; } // 距離テーブルの作成 rg = new float [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] = (float)Math.sqrt(x * x + y * y); if (seisu > -2) rg[i1][i2] = (int)(rg[i1][i2] + 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]; seq_w3 = new int [n_city]; seq_w4 = new int [n_city]; seq_w5 = 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; } } } } /****************/ /* 最適化の実行 */ /****************/ int Optimize () throws IOException, FileNotFoundException { int 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) { if (seisu > -2) System.out.println("***試行回数 " + n_tri + " 距離 " + (int)range); else 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) { if (seisu > -2) System.out.println("***試行回数 " + n_tri + " 距離 " + (int)range); else 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--; if (seisu > -2) System.out.println("***試行回数 " + n_tri + " 距離 " + (int)range); else System.out.println("***試行回数 " + n_tri + " 距離 " + (int)(range+0.5)); Output(out_lvl); } } // ワンステップづつ実行する場合 else { // 初期設定 range = kyori(n_city, seq, rg); // 初期状態の出力(図) wn.Draw(); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); // 初期状態の出力(文字) if (out_m >= 0 && Math.abs(out_lvl) > 0) { if (seisu > -2) System.out.println("***試行回数 " + n_tri + " 距離 " + (int)range); else System.out.println("***試行回数 " + n_tri + " 距離 " + range); Output(out_lvl); } // マウスによる実行 System.out.print("\n終了したらreturnキーを押してください\n"); in.readLine(); // 最終出力(文字) if (out_m >= 0) { if (seisu > -2) System.out.println("***試行回数 " + n_tri + " 距離 " + (int)range); else System.out.println("***試行回数 " + n_tri + " 距離 " + (int)(range+0.5)); Output(out_lvl); } } 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)); if (seisu > -2) out.println("***試行回数 " + n_tri + " 距離 " + (int)range + " 時間 " + now); else out.println("***試行回数 " + n_tri + " 距離 " + (int)(range+0.5) + " 時間 " + now); } if (out_m == 0) { for (i1 = 0; i1 < n_city; i1++) { n = seq[i1]; if (seisu > 0) out.println(" " + n + " " + (int)city[n][0] + " " + (int)city[n][1]); else 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() { double max, max1 = 0.0, r; int ch = 0, i0, i1, i2, i3, i4, k, k1 = 0, k2 = 0, k3, k4, n, nn, n1 = 0, n2 = 0, n3, n4, sw = 0, sw1 = 0, sw2; max = range; /* 近傍を可変 */ if (fix == 0) { // 初期設定(k=2) k = 2; for (i1 = 0; i1 < n_city; i1++) { seq_w4[i1] = seq[i1]; seq_w3[i1] = 0; } // 評価 sw2 = 0; for (i0 = 0; i0 < n_city-2 && sw2 < 2; i0++) { n = (i0 == 0) ? n_city-1 : n_city; for (i1 = i0+2; i1 < n && sw2 < 2; i1++) { // 相手の場所 k3 = i1; k4 = k3 + 1; if (k4 > n_city-1) k4 = 0; // 順番の入れ替え n3 = -1; for (i2 = 0; i2 < n_city && n3 < 0; i2++) { if (seq_w4[i2] == seq[i0+1]) n3 = i2 + 1; } nn = n3; n4 = -1; for (i2 = 0; i2 < n_city && n4 < 0; i2++) { if (nn > n_city-1) nn = 0; if (seq_w4[nn] == seq[k3] || seq_w4[nn] == seq[k4]) n4 = seq_w4[nn]; else nn++; } if (n4 == seq[k4]) { n4 = k3; k3 = k4; k4 = n4; } // 評価 seq_w1[0] = seq[k4]; seq_w1[1] = seq[i0+1]; n4 = -1; nn = 2; while (n4 < 0) { if (n3 > n_city-1) n3 = 0; seq_w1[nn] = seq_w4[n3]; if (seq_w4[n3] == seq[k3]) n4 = 1; nn++; n3++; } seq_w1[nn] = seq[i0]; nn++; n3 = -1; n4 = -1; for (i2 = 0; i2 < n_city && n3 < 0; i2++) { if (seq_w4[i2] == seq[i0]) { n3 = i2 - 1; if (n3 < 0) n3 = n_city - 1; } } while (n4 < 0) { if (seq_w4[n3] == seq[k4]) n4 = 1; else { seq_w1[nn] = seq_w4[n3]; nn++; n3--; if (n3 < 0) n3 = n_city - 1; } } r = kyori(n_city, seq_w1, rg); // 最適値の保存 if (sw2 == 0 || r < max1) { sw2 = 1; max1 = r; n1 = k3; n2 = k4; k1 = i0; k2 = i0 + 1; for (i2 = 0; i2 < n_city; i2++) seq_w5[i2] = seq_w1[i2]; if (sel > 0 && max1 < max) sw2 = 2; } } } // 最適値の保存と近傍の増加 if (sw2 > 0) { if (max1 < max) { sw = 1; max = max1; for (i1 = 0; i1 < n_city; i1++) seq_w2[i1] = seq_w5[i1]; } if (k < neib) { for (i1 = 0; i1 < n_city; i1++) seq_w4[i1] = seq_w5[i1]; seq_w3[k1] = 1; seq_w3[k2] = 1; seq_w3[n1] = 1; seq_w3[n2] = 1; k1 = n2; k++; } else sw1 = 1; } else sw1 = 1; // 実行(k>2) while (sw1 == 0) { // 評価 sw2 = 0; for (i1 = 0; i1 < n_city; i1++) { // 相手の場所 k3 = i1; k4 = k3 + 1; if (k4 > n_city-1) k4 = 0; if (seq_w3[k3] == 0 && seq_w3[k4] == 0) { // 順番の入れ替え n3 = -1; for (i2 = 0; i2 < n_city && n3 < 0; i2++) { if (seq_w4[i2] == seq[k2]) n3 = i2 + 1; } nn = n3; n4 = -1; for (i2 = 0; i2 < n_city && n4 < 0; i2++) { if (nn > n_city-1) nn = 0; if (seq_w4[nn] == seq[k3] || seq_w4[nn] == seq[k4]) n4 = seq_w4[nn]; else nn++; } if (n4 == seq[k4]) { n4 = k3; k3 = k4; k4 = n4; } // 評価 seq_w1[0] = seq[k4]; seq_w1[1] = seq[k2]; n4 = -1; nn = 2; while (n4 < 0) { if (n3 > n_city-1) n3 = 0; seq_w1[nn] = seq_w4[n3]; if (seq_w4[n3] == seq[k3]) n4 = 1; nn++; n3++; } seq_w1[nn] = seq[k1]; nn++; n3 = -1; n4 = -1; for (i2 = 0; i2 < n_city && n3 < 0; i2++) { if (seq_w4[i2] == seq[k1]) { n3 = i2 - 1; if (n3 < 0) n3 = n_city - 1; } } while (n4 < 0) { if (seq_w4[n3] == seq[k4]) n4 = 1; else { seq_w1[nn] = seq_w4[n3]; nn++; n3--; if (n3 < 0) n3 = n_city - 1; } } r = kyori(n_city, seq_w1, rg); // 最適値の保存 if (sw2 == 0 || r < max1) { sw2 = 1; max1 = r; n1 = k3; n2 = k4; for (i2 = 0; i2 < n_city; i2++) seq_w5[i2] = seq_w1[i2]; } } } // 最適値の保存と近傍の増加 if (sw2 > 0) { if (max1 < max) { sw = 1; max = max1; for (i1 = 0; i1 < n_city; i1++) seq_w2[i1] = seq_w5[i1]; } if (k < neib) { for (i1 = 0; i1 < n_city; i1++) seq_w4[i1] = seq_w5[i1]; seq_w3[n1] = 1; seq_w3[n2] = 1; k1 = n2; k++; } else sw1 = 1; } else sw1 = 1; } } /* 近傍を固定 */ else { 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 float kyori(int n_c, int [] p, float [][] rg) { float range = 0; int i1, n1, n2; 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_pt-------------- /**********************/ /* クラスWin_ptの定義 */ /**********************/ import java.awt.*; import java.awt.event.*; class Win_pt extends Frame { double ritu; // 表示倍率 private float min_x, max_x, min_y, max_y; // 都市の存在範囲 private int font; // フォントサイズ private int next, yoyu_x, yoyu_y; // 表示位置 private int r_sw; // 距離表示の有無 private int c_x, c_y; // 現在の対象領域 private Partition pt; /*************************************/ /* コンストラクタ */ /* pt : Partitionのオブジェクト */ /* city_i : 都市の位置データ */ /* font_i : フォントサイズ */ /* width,height : 表示範囲 */ /*************************************/ Win_pt (Partition pt_i, int font_i, int width, int height) { // Frameクラスのコンストラクタの呼び出し super("巡回セールスマン問題"); // 値の設定と領域の確保 double k1, k2; int i1; pt = pt_i; font = font_i; next = 70; yoyu_x = 30; yoyu_y = 80; // 描画領域の計算 min_x = pt.city[0][0]; max_x = pt.city[0][0]; min_y = pt.city[0][1]; max_y = pt.city[0][1]; for (i1 = 1; i1 < pt.n_city; i1++) { if (pt.city[i1][0] < min_x) min_x = pt.city[i1][0]; else { if (pt.city[i1][0] > max_x) max_x = pt.city[i1][0]; } if (pt.city[i1][1] < min_y) min_y = pt.city[i1][1]; else { if (pt.city[i1][1] > max_y) max_y = pt.city[i1][1]; } } k1 = (double)(width - 2 * yoyu_x) / (max_x - min_x); if (pt.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サイズ 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()); } /********************************/ /* 描画指示 */ /* sw : 距離表示の有無 */ /* c_y_i, c_x_i : 対象領域 */ /********************************/ void Draw(int sw, int c_y_i, int c_x_i) { r_sw = sw; c_y = c_y_i; c_x = c_x_i; repaint(); } /********/ /* 描画 */ /********/ public void paint (Graphics g) { int i1, i2, i3, k, n1, n2, size = 6, x1, x2, y1, y2; Font f; // 距離の表示 if (r_sw > 0) { f = new Font("TimesRoman", Font.BOLD, 25); g.setFont(f); if (pt.seisu > -2) g.drawString("Length : "+Integer.toString((int)pt.range), yoyu_x, yoyu_y-30); else g.drawString("Length : "+Integer.toString((int)(pt.range+0.5)), 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 < pt.n_p_y; i1++) { for (i2 = 0; i2 < pt.n_p_x; i2++) { if (pt.state[i1][i2] == 0) { if (i1 == c_y && i2 == c_x) g.setColor(Color.red); else g.setColor(Color.black); for (i3 = 0; i3 < pt.n_seq[i1][i2]; i3++) { n2 = pt.seq[i1][i2][i3]; x2 = yoyu_x + (int)(ritu * (pt.city[n2][0] - min_x)); y2 = yoyu_y + (int)(ritu * (max_y - pt.city[n2][1])); g.fillOval(x2, y2, size, size); if (font > 0) g.drawString(Integer.toString(n2), x2+k, y2-k); if (i3 > 0) { n1 = pt.seq[i1][i2][i3-1]; x1 = yoyu_x + (int)(ritu * (pt.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - pt.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); if (i3 == pt.n_seq[i1][i2]-1) { n1 = pt.seq[i1][i2][0]; x1 = yoyu_x + (int)(ritu * (pt.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - pt.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); } } } } } } } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } } ------------------------クラスWin_it-------------- /**********************/ /* クラスWin_itの定義 */ /**********************/ import java.awt.*; import java.awt.event.*; class Win_it extends Frame { double ritu; // 表示倍率 private float min_x, max_x, min_y, max_y; // 都市の存在範囲 private int font; // フォントサイズ 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); if (it.seisu > -2) g.drawString("Length : "+Integer.toString((int)it.range), yoyu_x, yoyu_y-30); else g.drawString("Length : "+Integer.toString((int)(it.range+0.5)), 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(クラスTSP)----------- /****************************/ /* 巡回セールスマン問題 */ /* (分割法) */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.StringTokenizer; public class TSP { /****************/ /* main program */ /****************/ public static void main(String args[]) throws IOException, FileNotFoundException { double mean; int i0, i1, n, nm, seed, max; String i_file, line; Partition pt; StringTokenizer dt; PrintStream out = null; BufferedReader in = new BufferedReader(new FileReader(args[0])); // 入力ミス if (args.length == 0) { System.out.print("***error ファイル名を入力して下さい\n"); System.exit(1); } // 入力OK else { // 入力データファイル名と問題数 line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); nm = Integer.parseInt(dt.nextToken()); for (i0 = 0; i0 < nm; i0++) { // 各問題の実行 line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); i_file = dt.nextToken(); dt.nextToken(); n = Integer.parseInt(dt.nextToken()); pt = new Partition(i_file); mean = 0.0; max = -1; // 乱数の初期値を変える for (i1 = 0; i1 < n; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); seed = Integer.parseInt(dt.nextToken()); System.out.println("\n+++++問題 " + i_file + " 乱数 " + seed + "+++++"); // 最適化 pt.Optimize(seed); // 最適値とその平均の計算 mean += pt.Max; if (max < 0 || pt.Max < max) max = pt.Max; } // 結果 if (pt.out_m <= 0) System.out.println(" -----最小 " + max + " 平均 " + mean/n + "-----"); else { out = new PrintStream(new FileOutputStream(pt.o_file, true)); out.println(" -----最小 " + max + " 平均 " + mean/n + "-----"); out.close(); } } in.close(); } } }
問題の数 2 問題 data/pr439.tsp 乱数の数 10 乱数 1 乱数 12 ・・・ 問題 data/kroA100.tsp 乱数の数 10 乱数 1 乱数 12 ・・・
都市の数 439 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 整数 1 出力(0:ディスプレイ,1:ファイル) -1 出力ファイル名 result/pr439 分割数 X 4 Y 3 最大試行回数 1000 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 3 都市番号 0 図の大きさ(幅,高さ) 1000 750 7125 11300 7225 11050 ・・・・・