データ例とプログラム
------------------------ケーススタディデータ------ 3 1 data/data10 12 data/data10 123 data/data10 ------------------------データファイル------------ 都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 result/kekka1 表示間隔 0 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 1 都市番号 20 図の大きさ(幅,高さ) 1000 750 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 ------------------------クラスIteration----------- /*************************/ /* クラスIterationの定義 */ /*************************/ import java.io.*; import java.util.Random; import java.util.Date; import java.util.StringTokenizer; 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-------------- /**********************/ /* クラスWin_itの定義 */ /**********************/ import java.awt.*; import java.awt.event.*; 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(クラス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 { int i1, n, seed[]; String i_file[], line; Iteration it; StringTokenizer dt; 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()); seed = new int [n]; i_file = new String [n]; for (i1 = 0; i1 < n; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); seed[i1] = Integer.parseInt(dt.nextToken()); i_file[i1] = dt.nextToken(); } in.close(); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { System.out.print("\n+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 it = new Iteration (seed[i1], i_file[i1]); // 最適化 it.Optimize(); } } } }
3 1 data/data10 12 data/data10 123 data/data10
都市の数 10 最大試行回数 3000 選択方法(0:最良,1:最初) 1 近傍(2or3) 3 出力レベル(負はファイル) 0 出力方法(-1:なし,0:すべて,1:評価値) 1 出力ファイル名 result/data10 表示間隔 0 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 1 都市番号 20 図の大きさ(幅,高さ) 1000 750 -58 37 55 -19 ・・・